<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="交易工具包-stripe" tabindex="-1"><a class="header-anchor" href="#交易工具包-stripe"><span>交易工具包 (Stripe)</span></a></h2>
<ul>
<li><a href="#introduction">引言</a></li>
<li><a href="#upgrading-cashier">交易工具包升级</a></li>
<li><a href="#installation">安装</a></li>
<li><a href="#configuration">配置</a>
<ul>
<li><a href="#billable-model">可计费模型</a></li>
<li><a href="#api-keys">API 密钥</a></li>
<li><a href="#currency-configuration">货币设置</a></li>
<li><a href="#tax-configuration">税务设置</a></li>
<li><a href="#logging">日志记录</a></li>
<li><a href="#using-custom-models">使用自定义模型</a></li>
</ul>
</li>
<li><a href="#quickstart">快速上手</a>
<ul>
<li><a href="#quickstart-selling-products">销售产品</a></li>
<li><a href="#quickstart-selling-subscriptions">销售订阅服务</a></li>
</ul>
</li>
<li><a href="#customers">客户管理</a>
<ul>
<li><a href="#retrieving-customers">获取客户信息</a></li>
<li><a href="#creating-customers">创建客户</a></li>
<li><a href="#updating-customers">更新客户信息</a></li>
<li><a href="#balances">余额管理</a></li>
<li><a href="#tax-ids">税号管理</a></li>
<li><a href="#syncing-customer-data-with-stripe">与 Stripe 同步客户数据</a></li>
<li><a href="#billing-portal">账单门户</a></li>
</ul>
</li>
<li><a href="#payment-methods">支付方式</a>
<ul>
<li><a href="#storing-payment-methods">保存支付方式</a></li>
<li><a href="#retrieving-payment-methods">获取支付方式</a></li>
<li><a href="#payment-method-presence">检查支付方式是否存在</a></li>
<li><a href="#updating-the-default-payment-method">更新默认支付方式</a></li>
<li><a href="#adding-payment-methods">添加支付方式</a></li>
<li><a href="#deleting-payment-methods">删除支付方式</a></li>
</ul>
</li>
<li><a href="#subscriptions">订阅管理</a>
<ul>
<li><a href="#creating-subscriptions">创建订阅</a></li>
<li><a href="#checking-subscription-status">检查订阅状态</a></li>
<li><a href="#changing-prices">更改价格</a></li>
<li><a href="#subscription-quantity">订阅数量</a></li>
<li><a href="#subscriptions-with-multiple-products">多产品订阅</a></li>
<li><a href="#multiple-subscriptions">多重订阅</a></li>
<li><a href="#metered-billing">按量计费</a></li>
<li><a href="#subscription-taxes">订阅税费</a></li>
<li><a href="#subscription-anchor-date">订阅起始日期</a></li>
<li><a href="#cancelling-subscriptions">取消订阅</a></li>
<li><a href="#resuming-subscriptions">恢复订阅</a></li>
</ul>
</li>
<li><a href="#subscription-trials">订阅试用期</a>
<ul>
<li><a href="#with-payment-method-up-front">预先提供支付方式</a></li>
<li><a href="#without-payment-method-up-front">无需预先提供支付方式</a></li>
<li><a href="#extending-trials">延长试用期</a></li>
</ul>
</li>
<li><a href="#handling-stripe-webhooks">处理 Stripe Webhooks</a>
<ul>
<li><a href="#defining-webhook-event-handlers">定义 Webhook 事件处理器</a></li>
<li><a href="#verifying-webhook-signatures">验证 Webhook 签名</a></li>
</ul>
</li>
<li><a href="#single-charges">一次性收费</a>
<ul>
<li><a href="#simple-charge">简单收费</a></li>
<li><a href="#charge-with-invoice">带发票的收费</a></li>
<li><a href="#creating-payment-intents">创建支付意向</a></li>
<li><a href="#refunding-charges">退款处理</a></li>
</ul>
</li>
<li><a href="#checkout">结账流程</a>
<ul>
<li><a href="#product-checkouts">产品结账</a></li>
<li><a href="#single-charge-checkouts">一次性收费结账</a></li>
<li><a href="#subscription-checkouts">订阅结账</a></li>
<li><a href="#collecting-tax-ids">收集税号</a></li>
<li><a href="#guest-checkouts">访客结账</a></li>
</ul>
</li>
<li><a href="#invoices">发票管理</a>
<ul>
<li><a href="#retrieving-invoices">获取发票</a></li>
<li><a href="#upcoming-invoices">即将到来的发票</a></li>
<li><a href="#previewing-subscription-invoices">预览订阅发票</a></li>
<li><a href="#generating-invoice-pdfs">生成发票 PDF</a></li>
</ul>
</li>
<li><a href="#handling-failed-payments">处理支付失败</a>
<ul>
<li><a href="#confirming-payments">确认支付</a></li>
</ul>
</li>
<li><a href="#strong-customer-authentication">强客户认证 (SCA)</a>
<ul>
<li><a href="#payments-requiring-additional-confirmation">需要额外确认的支付</a></li>
<li><a href="#off-session-payment-notifications">离线支付通知</a></li>
</ul>
</li>
<li><a href="#stripe-sdk">Stripe SDK</a></li>
<li><a href="#testing">测试</a></li>
</ul>
<h2 id="引言" tabindex="-1"><a class="header-anchor" href="#引言"><span>引言</span></a></h2>
<p><a href="https://github.com/laravel/cashier-stripe" target="_blank" rel="noopener noreferrer">Laravel 交易工具包</a> 为 <a href="https://stripe.com/" target="_blank" rel="noopener noreferrer">Stripe</a> 的订阅计费服务提供了一个富有表现力且流畅的接口。它几乎处理了所有你不愿编写的订阅计费样板代码。除了基本的订阅管理外，交易工具包还可以处理优惠券、切换订阅、订阅「数量」、取消宽限期，甚至生成发票 PDF。</p>
<h2 id="升级交易工具包" tabindex="-1"><a class="header-anchor" href="#升级交易工具包"><span>升级交易工具包</span></a></h2>
<p>在升级到新版本的工具包时，务必仔细阅读 <a href="https://github.com/laravel/cashier-stripe/blob/master/UPGRADE.md" target="_blank" rel="noopener noreferrer">升级指南</a>。</p>
<blockquote>
<p><strong>警告</strong><br>
为了防止破坏性变更，交易工具包使用固定的 Stripe API 版本。交易工具包 15 使用 Stripe API 版本 <code v-pre>2023-10-16</code> 。Stripe API 版本将在次要版本中更新，以便利用 Stripe 的新功能和改进。</p>
</blockquote>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<p>首先，使用 Composer 包管理器安装 Stripe 的交易工具包：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require laravel/cashier</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>安装包后，使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Cashier 的迁移文件：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--tag</span><span class="token operator">=</span><span class="token string">"cashier-migrations"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>然后，迁移你的数据库：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>交易工具包的迁移将在你的 <code v-pre>users</code> 表中添加几个列。它们还将创建一个新的 <code v-pre>subscriptions</code> 表来保存所有客户的订阅，以及一个 <code v-pre>subscription_items</code> 表用于多价格订阅。</p>
<p>如果你愿意，也可以使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Cashier 的配置文件：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--tag</span><span class="token operator">=</span><span class="token string">"cashier-config"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>最后，为确保交易工具包正确处理所有 Stripe 事件，请记得 <a href="#handling-stripe-webhooks">配置交易工具包的 webhook 处理</a>。</p>
<blockquote>
<p><strong>警告</strong><br>
Stripe 建议用于存储 Stripe 标识符的任何列都应区分大小写。因此，在使用 MySQL 时，你应确保 stripe_id 列的排序规则设置为 utf8_bin。有关此内容的更多信息可以在 <a href="https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible" target="_blank" rel="noopener noreferrer">Stripe 文档</a> 中找到。</p>
</blockquote>
<h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<h3 id="可计费模型" tabindex="-1"><a class="header-anchor" href="#可计费模型"><span>可计费模型</span></a></h3>
<p>在使用 Cashier 之前，请将 <code v-pre>Billable</code> 特性添加到你的可计费模型定义中。通常，这将是 <code v-pre>App\Models\User</code> 模型。该特性提供了各种方法，允许你执行常见的计费任务，如创建订阅、应用优惠券和更新付款方式信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Billable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Billable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Cashier 假定你的可计费模型将是 Laravel 提供的 <code v-pre>App\Models\User</code> 类。如果你希望更改这一点，可以通过 <code v-pre>useCustomerModel</code> 方法指定不同的模型。这个方法通常应该在你的 <code v-pre>AppServiceProvider</code> 类的 <code v-pre>boot</code> 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Bootstrap any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">useCustomerModel</span><span class="token punctuation">(</span><span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
如果你使用的模型不是 Laravel 提供的 <code v-pre>App\Models\User</code> 模型，你需要发布并修改提供的 <a href="#installation">Cashier 迁移</a>，以匹配你的替代模型的表名。</p>
</blockquote>
<h3 id="api-密钥" tabindex="-1"><a class="header-anchor" href="#api-密钥"><span>API 密钥</span></a></h3>
<p>接下来，你应在应用程序的 <code v-pre>.env</code> 文件中配置你的 Stripe API 密钥。你可以从 Stripe 控制面板中检索你的 Stripe API 密钥：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">STRIPE_KEY</span><span class="token punctuation">=</span><span class="token value attr-value">your-stripe-key</span></span>
<span class="line"><span class="token key attr-name">STRIPE_SECRET</span><span class="token punctuation">=</span><span class="token value attr-value">your-stripe-secret</span></span>
<span class="line"><span class="token key attr-name">STRIPE_WEBHOOK_SECRET</span><span class="token punctuation">=</span><span class="token value attr-value">your-stripe-webhook-secret</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
请确保在应用程序的 <code v-pre>.env</code> 文件中定义了 <code v-pre>STRIPE_WEBHOOK_SECRET</code> 环境变量，因为该变量用于确保传入的 Webhooks 实际来自 Stripe。</p>
</blockquote>
<h3 id="货币配置" tabindex="-1"><a class="header-anchor" href="#货币配置"><span>货币配置</span></a></h3>
<p>Cashier 的默认货币是美元（USD）。你可以通过在应用程序的 <code v-pre>.env</code> 文件中设置 <code v-pre>CASHIER_CURRENCY</code> 环境变量来更改默认货币：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_CURRENCY</span><span class="token punctuation">=</span><span class="token value attr-value">eur</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>除了配置 Cashier 的货币外，你还可以指定一个区域设置，用于在发票上显示货币值时格式化。在内部，Cashier 使用 <a href="https://www.php.net/manual/en/class.numberformatter.php" target="_blank" rel="noopener noreferrer">PHP 的 <code v-pre>NumberFormatter</code> 类</a> 来设置货币区域设置：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_CURRENCY_LOCALE</span><span class="token punctuation">=</span><span class="token value attr-value">nl_BE</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
若要使用除 <code v-pre>en</code> 外的区域设置，请确保在服务器上安装并配置了 <code v-pre>ext-intl</code> PHP 扩展。</p>
</blockquote>
<h3 id="税务配置" tabindex="-1"><a class="header-anchor" href="#税务配置"><span>税务配置</span></a></h3>
<p>由于 <a href="https://stripe.com/tax" target="_blank" rel="noopener noreferrer">Stripe Tax</a> 的支持，可以自动为 Stripe 生成的所有发票计算税费。你可以通过在应用程序的 <code v-pre>App\Providers\AppServiceProvider</code> 类的 <code v-pre>boot</code> 方法中调用 <code v-pre>calculateTaxes</code> 方法来启用自动税费计算：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Bootstrap any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">calculateTaxes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦启用了税费计算，任何生成的新订阅和任何一次性发票都将接收到自动税费计算。</p>
<p>为使此功能正常工作，客户的账单详细信息，如客户姓名、地址和税号，需要与 Stripe 同步。你可以使用 Cashier 提供的 <a href="#syncing-customer-data-with-stripe">客户数据同步</a> 和 <a href="#tax-ids">税号</a> 方法来实现这一点。</p>
<blockquote>
<p><strong>警告</strong><br>
不会为 <a href="#single-charges">单次收费</a> 或 <a href="#single-charge-checkouts">单次收费结账</a> 计算税费。</p>
</blockquote>
<h3 id="日志记录" tabindex="-1"><a class="header-anchor" href="#日志记录"><span>日志记录</span></a></h3>
<p>Cashier 允许你指定在记录致命的 Stripe 错误时要使用的日志通道。你可以通过在应用程序的 <code v-pre>.env</code> 文件中定义 <code v-pre>CASHIER_LOGGER</code> 环境变量来指定日志通道：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_LOGGER</span><span class="token punctuation">=</span><span class="token value attr-value">stack</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>通过对 Stripe 的 API 调用生成的异常将通过你的应用程序的默认日志通道进行记录。</p>
<h3 id="使用自定义模型" tabindex="-1"><a class="header-anchor" href="#使用自定义模型"><span>使用自定义模型</span></a></h3>
<p>你可以通过定义自己的模型并扩展相应的 Cashier 模型来自由扩展 Cashier 内部使用的模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Subscription</span> <span class="token keyword">as</span> CashierSubscription<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Subscription</span> <span class="token keyword">extends</span> <span class="token class-name">CashierSubscription</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>定义完你的模型后，你可以通过 <code v-pre>Laravel\Cashier\Cashier</code> 类指示 Cashier 使用你的自定义模型。通常，你应该在应用程序的 <code v-pre>App\Providers\AppServiceProvider</code> 类的 <code v-pre>boot</code> 方法中告知 Cashier 关于你的自定义模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Subscription</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>SubscriptionItem</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Bootstrap any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">useSubscriptionModel</span><span class="token punctuation">(</span><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">useSubscriptionItemModel</span><span class="token punctuation">(</span><span class="token class-name static-context">SubscriptionItem</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="快速入门" tabindex="-1"><a class="header-anchor" href="#快速入门"><span>快速入门</span></a></h2>
<h3 id="销售产品" tabindex="-1"><a class="header-anchor" href="#销售产品"><span>销售产品</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
在使用 Stripe Checkout 之前，你应该在 Stripe 仪表板中定义具有固定价格的产品。此外，你应该<a href="#handling-stripe-webhooks">配置 Cashier 的 Webhook 处理</a>。</p>
</blockquote>
<p>通过你的应用程序提供产品和订阅计费可能会让人望而生畏。然而，由于 Cashier 和 <a href="https://stripe.com/payments/checkout" target="_blank" rel="noopener noreferrer">Stripe Checkout</a> 的支持，你可以轻松构建现代、强大的支付集成。</p>
<p>要为非重复的单次收费产品向客户收费，我们将利用 Cashier 将客户引导到 Stripe Checkout，在那里他们将提供他们的付款信息并确认购买。一旦通过 Checkout 进行付款，客户将被重定向到你在应用程序中选择的成功 URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$stripePriceId</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'price_deluxe_album'</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$quantity</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token variable">$stripePriceId</span> <span class="token operator">=></span> <span class="token variable">$quantity</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-cancel'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/checkout/success'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'checkout.success'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/checkout/cancel'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'checkout.cancel'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-cancel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如上面的示例所示，我们将利用 Cashier 提供的 <code v-pre>checkout</code> 方法将客户重定向到 Stripe Checkout，针对给定的「价格标识符」。在使用 Stripe 时，「价格」指的是<a href="https://stripe.com/docs/products-prices/how-products-and-prices-work" target="_blank" rel="noopener noreferrer">针对特定产品定义的价格</a>。</p>
<p>如果需要，<code v-pre>checkout</code> 方法将自动在 Stripe 中创建一个客户，并将该 Stripe 客户记录连接到你应用程序数据库中相应的用户。完成结账会话后，客户将被重定向到专用的成功或取消页面，你可以在那里向客户显示信息性消息。</p>
<h4 id="向-stripe-checkout-提供元数据" tabindex="-1"><a class="header-anchor" href="#向-stripe-checkout-提供元数据"><span>向 Stripe Checkout 提供元数据</span></a></h4>
<p>在销售产品时，通过你自己的应用程序定义的 <code v-pre>Cart</code> 和 <code v-pre>Order</code> 模型通常用于跟踪已完成的订单和已购买的产品。当将客户重定向到 Stripe Checkout 完成购买时，你可能需要提供一个现有的订单标识符，以便在客户被重定向回你的应用程序时将已完成的购买与相应的订单关联起来。</p>
<p>为实现这一点，你可以向 <code v-pre>checkout</code> 方法提供一个 <code v-pre>metadata</code> 数组。假设在我们的应用程序中，当用户开始结账流程时，会创建一个待处理的 <code v-pre>Order</code>。请记住，本示例中的 <code v-pre>Cart</code> 和 <code v-pre>Order</code> 模型仅用于说明，并非由 Cashier 提供。你可以根据你自己应用程序的需求自由实现这些概念：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Cart</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/cart/{cart}/checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Cart</span> <span class="token variable">$cart</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$order</span> <span class="token operator">=</span> <span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'cart_id'</span> <span class="token operator">=></span> <span class="token variable">$cart</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_ids'</span> <span class="token operator">=></span> <span class="token variable">$cart</span><span class="token operator">-></span><span class="token property">price_ids</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'status'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'incomplete'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token variable">$order</span><span class="token operator">-></span><span class="token property">price_ids</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token operator">.</span><span class="token string single-quoted-string">'?session_id={CHECKOUT_SESSION_ID}'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-cancel'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'metadata'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'order_id'</span> <span class="token operator">=></span> <span class="token variable">$order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如上面的示例所示，当用户开始结账流程时，我们将为 <code v-pre>checkout</code> 方法提供所有购物车/订单关联的 Stripe 价格标识符。当客户将它们添加时，你的应用程序负责将这些项目与「购物车」或订单关联起来。我们还通过 <code v-pre>metadata</code> 数组向 Stripe Checkout 会话提供订单的 ID。最后，我们在结账成功路由中添加了 <code v-pre>CHECKOUT_SESSION_ID</code> 模板变量。当 Stripe 将客户重定向回你的应用程序时，此模板变量将自动填充为 Checkout 会话 ID。</p>
<p>接下来，让我们构建结账成功路由。这是用户在通过 Stripe Checkout 完成购买后将被重定向到的路由。在这个路由中，我们可以检索 Stripe Checkout 会话 ID 和关联的 Stripe Checkout 实例，以便访问我们提供的元数据并相应地更新客户的订单：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/checkout/success'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$sessionId</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'session_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$sessionId</span> <span class="token operator">===</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$session</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">stripe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">checkout</span><span class="token operator">-></span><span class="token property">sessions</span><span class="token operator">-></span><span class="token function">retrieve</span><span class="token punctuation">(</span><span class="token variable">$sessionId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$session</span><span class="token operator">-></span><span class="token property">payment_status</span> <span class="token operator">!==</span> <span class="token string single-quoted-string">'paid'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$orderId</span> <span class="token operator">=</span> <span class="token variable">$session</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'metadata'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'order_id'</span><span class="token punctuation">]</span> <span class="token operator">??</span> <span class="token constant">null</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$order</span> <span class="token operator">=</span> <span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token function">findOrFail</span><span class="token punctuation">(</span><span class="token variable">$orderId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$order</span><span class="token operator">-></span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'status'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'completed'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'order'</span> <span class="token operator">=></span> <span class="token variable">$order</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>请参考 Stripe 的文档以获取有关<a href="https://stripe.com/docs/api/checkout/sessions/object" target="_blank" rel="noopener noreferrer">Checkout 会话对象中包含的数据</a>的更多信息。</p>
<h3 id="销售订阅" tabindex="-1"><a class="header-anchor" href="#销售订阅"><span>销售订阅</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
在使用 Stripe Checkout 之前，你应该在 Stripe 仪表板中定义具有固定价格的产品。此外，你应该<a href="#handling-stripe-webhooks">配置 Cashier 的 Webhook 处理</a>。</p>
</blockquote>
<p>通过你的应用程序提供产品和订阅计费可能会让人望而生畏。然而，借助 Cashier 和 <a href="https://stripe.com/payments/checkout" target="_blank" rel="noopener noreferrer">Stripe Checkout</a>，你可以轻松构建现代、强大的支付集成。</p>
<p>要学习如何使用 Cashier 和 Stripe Checkout 出售订阅，让我们考虑一个简单的情景：一个具有基本月度（<code v-pre>price_basic_monthly</code>）和年度（<code v-pre>price_basic_yearly</code>）计划的订阅服务。这两个价格可以在我们的 Stripe 仪表板中作为「Basic」产品（<code v-pre>pro_basic</code>）进行分组。此外，我们的订阅服务可能还提供 <code v-pre>pro_expert</code> 作为专家计划。</p>
<p>首先，让我们了解客户如何订阅我们的服务。当然，你可以想象客户可能会在我们应用程序的定价页面上为基本计划点击「订阅」按钮。这个按钮或链接应该将用户重定向到一个 Laravel 路由，为他们选择的计划创建 Stripe Checkout 会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_basic_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">trialDays</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">allowPromotionCodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-success-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-cancel-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如上面的示例所示，我们将客户重定向到一个 Stripe Checkout 会话，让他们订阅我们的基本计划。在成功结账或取消后，客户将被重定向回我们在 <code v-pre>checkout</code> 方法中提供的 URL。为了知道他们的订阅实际开始的时间（因为一些支付方式需要几秒钟来处理），我们还需要<a href="#handling-stripe-webhooks">配置 Cashier 的 Webhook 处理</a>。</p>
<p>现在客户可以开始订阅了，我们需要限制应用程序的某些部分，以便只有订阅用户才能访问它们。当然，我们可以始终通过 Cashier 的 <code v-pre>Billable</code> trait 提供的 <code v-pre>subscribed</code> 方法来确定用户当前的订阅状态：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if ($user-&gt;subscribed())</span>
<span class="line">    &lt;p&gt;你已订阅。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>我们甚至可以轻松确定用户是否订阅了特定产品或价格：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if ($user-&gt;subscribedToProduct('pro_basic'))</span>
<span class="line">    &lt;p&gt;你已订阅我们的基础产品。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span>
<span class="line">@if ($user-&gt;subscribedToPrice('price_basic_monthly'))</span>
<span class="line">    &lt;p&gt;你已订阅我们的月度基础计划。&lt;/p&gt;</span>
<span class="line">@endif</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="创建订阅中间件" tabindex="-1"><a class="header-anchor" href="#创建订阅中间件"><span>创建订阅中间件</span></a></h4>
<p>为了方便起见，你可能希望创建一个<a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">中间件</a>，用于确定传入请求是否来自已订阅用户。一旦定义了这个中间件，你可以轻松地将其分配给一个路由，以防止未订阅的用户访问该路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Symfony<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>HttpFoundation<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Subscribed</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理传入请求。</span>
<span class="line">  */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 将用户重定向到计费页面并要求他们订阅...</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦定义了中间件，你可以将其分配给一个路由：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>Subscribed</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/dashboard'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name static-context">Subscribed</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="允许客户管理他们的计费计划" tabindex="-1"><a class="header-anchor" href="#允许客户管理他们的计费计划"><span>允许客户管理他们的计费计划</span></a></h4>
<p>当然，客户可能希望将他们的订阅计划更改为另一个产品或「层级」。允许这样做的最简单方法是将客户引导到 Stripe 的<a href="https://stripe.com/docs/no-code/customer-portal" target="_blank" rel="noopener noreferrer">客户计费门户</a>，该门户提供了一个托管用户界面，允许客户下载发票、更新他们的付款方式以及更改订阅计划。</p>
<p>首先，在你的应用程序中定义一个链接或按钮，将用户重定向到一个 Laravel 路由，我们将利用该路由来启动一个计费门户会话：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">&lt;a href=&quot;{{ route('billing') }}&quot;&gt;</span>
<span class="line">    计费</span>
<span class="line">&lt;/a&gt;</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，让我们定义一个路由，启动一个 Stripe 客户计费门户会话，并将用户重定向到门户。<code v-pre>redirectToBillingPortal</code> 方法接受用户在退出门户时应返回的 URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectToBillingPortal</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'dashboard'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
只要你已经配置了 Cashier 的 Webhook 处理，Cashier 将通过检查来自 Stripe 的传入 Webhook 自动保持你的应用程序的 Cashier 相关数据库表同步。因此，例如，当用户通过 Stripe 的客户计费门户取消订阅时，Cashier 将接收相应的 Webhook 并在你的应用程序数据库中将订阅标记为「已取消」。</p>
</blockquote>
<h2 id="客户" tabindex="-1"><a class="header-anchor" href="#客户"><span>客户</span></a></h2>
<h3 id="检索客户" tabindex="-1"><a class="header-anchor" href="#检索客户"><span>检索客户</span></a></h3>
<p>你可以使用 <code v-pre>Cashier::findBillable</code> 方法通过他们的 Stripe ID 检索客户。该方法将返回一个可计费模型的实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">findBillable</span><span class="token punctuation">(</span><span class="token variable">$stripeId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="创建客户" tabindex="-1"><a class="header-anchor" href="#创建客户"><span>创建客户</span></a></h3>
<p>有时，你可能希望创建一个 Stripe 客户而不开始订阅。你可以使用 <code v-pre>createAsStripeCustomer</code> 方法来实现这一点：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeCustomer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsStripeCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>一旦客户在 Stripe 中创建，你可以在以后的某个日期开始订阅。你可以提供一个可选的 <code v-pre>$options</code> 数组，以传递任何额外的<a href="https://stripe.com/docs/api/customers/create" target="_blank" rel="noopener noreferrer">由 Stripe API 支持的客户创建参数</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeCustomer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsStripeCustomer</span><span class="token punctuation">(</span><span class="token variable">$options</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想为可计费模型返回 Stripe 客户对象，可以使用 <code v-pre>asStripeCustomer</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeCustomer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">asStripeCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想要检索给定可计费模型的 Stripe 客户对象，但不确定该可计费模型是否已经是 Stripe 中的客户，可以使用 <code v-pre>createOrGetStripeCustomer</code> 方法。如果该客户在 Stripe 中不存在，该方法将创建一个新的客户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeCustomer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createOrGetStripeCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="更新客户" tabindex="-1"><a class="header-anchor" href="#更新客户"><span>更新客户</span></a></h3>
<p>有时，你可能希望直接使用额外信息更新 Stripe 客户。你可以使用 <code v-pre>updateStripeCustomer</code> 方法来实现这一点。该方法接受一个 <a href="https://stripe.com/docs/api/customers/update" target="_blank" rel="noopener noreferrer">Stripe API 支持的客户更新选项数组</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeCustomer</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">updateStripeCustomer</span><span class="token punctuation">(</span><span class="token variable">$options</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="余额" tabindex="-1"><a class="header-anchor" href="#余额"><span>余额</span></a></h3>
<p>Stripe 允许你为客户的「余额」增加或减少金额。之后，这个余额将在新的发票上得到增加或减少。你可以使用可计费模型上提供的 <code v-pre>balance</code> 方法来检查客户的总余额。<code v-pre>balance</code> 方法将以客户的货币形式返回一个格式化的余额字符串：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$balance</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">balance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要为客户的余额增加金额，你可以向 <code v-pre>creditBalance</code> 方法提供一个值。如果需要，你也可以提供一个描述：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">creditBalance</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'高级客户充值。'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>向 <code v-pre>debitBalance</code> 方法提供一个值将减少客户的余额：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">debitBalance</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'不良使用惩罚。'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>applyBalance</code> 方法将为客户创建新的余额交易记录。你可以使用 <code v-pre>balanceTransactions</code> 方法检索这些交易记录，这可能对提供客户审查的积分和借记日志很有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 检索所有交易记录...</span></span>
<span class="line"><span class="token variable">$transactions</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">balanceTransactions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$transactions</span> <span class="token keyword">as</span> <span class="token variable">$transaction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 交易金额...</span></span>
<span class="line">    <span class="token variable">$amount</span> <span class="token operator">=</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">amount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// $2.31</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 在可能的情况下检索相关发票...</span></span>
<span class="line">    <span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$transaction</span><span class="token operator">-></span><span class="token function">invoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="税务识别号" tabindex="-1"><a class="header-anchor" href="#税务识别号"><span>税务识别号</span></a></h3>
<p>Cashier 提供了一个简单的方法来管理客户的税务识别号。例如，可以使用 <code v-pre>taxIds</code> 方法来检索分配给客户的所有<a href="https://stripe.com/docs/api/customer_tax_ids/object" target="_blank" rel="noopener noreferrer">税务识别号</a>作为一个集合：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$taxIds</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">taxIds</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你也可以通过其标识符为客户检索特定的税务识别号：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$taxId</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findTaxId</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'txi_belgium'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>通过向 <code v-pre>createTaxId</code> 方法提供有效的<a href="https://stripe.com/docs/api/customer_tax_ids/object#tax_id_object-type" target="_blank" rel="noopener noreferrer">type</a>和值，你可以创建一个新的税务识别号：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$taxId</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createTaxId</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'eu_vat'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'BE0123456789'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>createTaxId</code> 方法将立即将 VAT ID 添加到客户的账户中。<a href="https://stripe.com/docs/invoicing/customer/tax-ids#validation" target="_blank" rel="noopener noreferrer">Stripe 还会对 VAT ID 进行验证</a>；但是，这是一个异步过程。你可以通过订阅 <code v-pre>customer.tax_id.updated</code> Webhook 事件并检查<a href="https://stripe.com/docs/api/customer_tax_ids/object#tax_id_object-verification" target="_blank" rel="noopener noreferrer">VAT ID 的 <code v-pre>verification</code> 参数</a>来获得验证更新的通知。有关处理 Webhooks 的更多信息，请参阅<a href="#handling-stripe-webhooks">定义 Webhook 处理程序的文档</a>。</p>
<p>你可以使用 <code v-pre>deleteTaxId</code> 方法删除税务识别号：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">deleteTaxId</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'txi_belgium'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="将客户数据与-stripe-同步" tabindex="-1"><a class="header-anchor" href="#将客户数据与-stripe-同步"><span>将客户数据与 Stripe 同步</span></a></h3>
<p>通常，当你的应用程序用户更新他们的姓名、电子邮件地址或其他也存储在 Stripe 中的信息时，你应该通知 Stripe 进行更新。通过这样做，Stripe 中的信息副本将与你的应用程序保持同步。</p>
<p>要自动化这一过程，你可以在可计费模型上定义一个事件监听器，以响应模型的 <code v-pre>updated</code> 事件。然后，在你的事件监听器中，你可以在模型上调用 <code v-pre>syncStripeCustomerDetails</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token keyword">function</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>queueable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 模型的 "booted" 方法。</span>
<span class="line">  */</span></span>
<span class="line"><span class="token keyword">protected</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">booted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">updated</span><span class="token punctuation">(</span><span class="token function">queueable</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$customer</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">hasStripeId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">syncStripeCustomerDetails</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在，每当你的客户模型被更新时，其信息将与 Stripe 同步。为了方便起见，在创建客户时，Cashier 将自动将客户的信息与 Stripe 同步。</p>
<p>你可以通过覆盖 Cashier 提供的各种方法来自定义用于将客户信息与 Stripe 同步的列。例如，你可以覆盖 <code v-pre>stripeName</code> 方法，以自定义应被视为客户「姓名」的属性，当 Cashier 将客户信息同步到 Stripe 时：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取应同步到 Stripe 的客户名称。</span>
<span class="line">  */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">stripeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">company_name</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>类似地，你可以覆盖 <code v-pre>stripeEmail</code>、<code v-pre>stripePhone</code>、<code v-pre>stripeAddress</code> 和 <code v-pre>stripePreferredLocales</code> 方法。这些方法将在<a href="https://stripe.com/docs/api/customers/update" target="_blank" rel="noopener noreferrer">更新 Stripe 客户对象</a>时将信息同步到相应的客户参数。如果你希望完全控制客户信息同步过程，你可以覆盖 <code v-pre>syncStripeCustomerDetails</code> 方法。</p>
<h3 id="计费门户" tabindex="-1"><a class="header-anchor" href="#计费门户"><span>计费门户</span></a></h3>
<p>Stripe 提供了<a href="https://stripe.com/docs/billing/subscriptions/customer-portal" target="_blank" rel="noopener noreferrer">一个简单的设置计费门户的方法</a>，让你的客户可以管理他们的订阅、支付方式，并查看他们的账单历史。你可以通过在控制器或路由中在可计费模型上调用 <code v-pre>redirectToBillingPortal</code> 方法来将用户重定向到计费门户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing-portal'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectToBillingPortal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，当用户完成管理他们的订阅后，他们可以通过 Stripe 计费门户内的链接返回到你应用程序的 <code v-pre>home</code> 路由。你可以通过将自定义 URL 作为参数传递给 <code v-pre>redirectToBillingPortal</code> 方法来提供用户应返回的自定义 URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing-portal'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">redirectToBillingPortal</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要生成到计费门户的 URL 而不生成 HTTP 重定向响应，你可以调用 <code v-pre>billingPortalUrl</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$url</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">billingPortalUrl</span><span class="token punctuation">(</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="付款方式" tabindex="-1"><a class="header-anchor" href="#付款方式"><span>付款方式</span></a></h2>
<h3 id="存储付款方式" tabindex="-1"><a class="header-anchor" href="#存储付款方式"><span>存储付款方式</span></a></h3>
<p>为了使用 Stripe 创建订阅或执行「一次性」收费，你需要存储一个付款方式并从 Stripe 检索其标识符。为了实现这一目的，根据你计划将付款方式用于订阅还是单次收费，采取的方法有所不同，因此我们将在下面分别讨论这两种情况。</p>
<h4 id="订阅的付款方式" tabindex="-1"><a class="header-anchor" href="#订阅的付款方式"><span>订阅的付款方式</span></a></h4>
<p>当为将来使用订阅的客户存储信用卡信息时，必须使用 Stripe 的「设置意向」API 来安全地收集客户的付款方式详细信息。「设置意向」向 Stripe 指示要收取客户的付款方式。Cashier 的 <code v-pre>Billable</code> 特性包括 <code v-pre>createSetupIntent</code> 方法，用于轻松创建新的设置意向。你应该从将呈现收集客户付款方式详细信息的表单的路由或控制器中调用此方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-payment-method'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'intent'</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createSetupIntent</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在创建设置意向并将其传递给视图后，你应该将其密钥附加到将收集付款方式的元素上。例如，考虑以下「更新付款方式」表单：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-holder-name<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token comment">&lt;!-- Stripe 元素占位符 --></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-element<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-button<span class="token punctuation">"</span></span> <span class="token attr-name">data-secret</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ $intent->client_secret }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    更新付款方式</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，可以使用 Stripe.js 库将<a href="https://stripe.com/docs/stripe-js" target="_blank" rel="noopener noreferrer">Stripe 元素</a>附加到表单中，并安全地收集客户的付款详细信息：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://js.stripe.com/v3/<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"></span>
<span class="line">    <span class="token keyword">const</span> stripe <span class="token operator">=</span> <span class="token function">Stripe</span><span class="token punctuation">(</span><span class="token string">'stripe-public-key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">const</span> elements <span class="token operator">=</span> stripe<span class="token punctuation">.</span><span class="token function">elements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token keyword">const</span> cardElement <span class="token operator">=</span> elements<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'card'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    cardElement<span class="token punctuation">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string">'#card-element'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，可以验证卡片并使用<a href="https://stripe.com/docs/js/setup_intents/confirm_card_setup" target="_blank" rel="noopener noreferrer">Stripe 的 <code v-pre>confirmCardSetup</code> 方法</a>从 Stripe 获取安全的「付款方式标识符」：</p>
<div class="language-javascript line-numbers-mode" data-highlighter="prismjs" data-ext="js" data-title="js"><pre v-pre class="language-javascript"><code><span class="line"><span class="token keyword">const</span> cardHolderName <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'card-holder-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> cardButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'card-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> clientSecret <span class="token operator">=</span> cardButton<span class="token punctuation">.</span>dataset<span class="token punctuation">.</span>secret<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">cardButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token punctuation">{</span> setupIntent<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> stripe<span class="token punctuation">.</span><span class="token function">confirmCardSetup</span><span class="token punctuation">(</span></span>
<span class="line">        clientSecret<span class="token punctuation">,</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token literal-property property">payment_method</span><span class="token operator">:</span> <span class="token punctuation">{</span></span>
<span class="line">                <span class="token literal-property property">card</span><span class="token operator">:</span> cardElement<span class="token punctuation">,</span></span>
<span class="line">                <span class="token literal-property property">billing_details</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> cardHolderName<span class="token punctuation">.</span>value <span class="token punctuation">}</span></span>
<span class="line">            <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 向用户显示「error.message」...</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 卡片已成功验证...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在 Stripe 验证卡片后，你可以将生成的 <code v-pre>setupIntent.payment_method</code> 标识符传递给你的 Laravel 应用程序，在那里它可以附加到客户。付款方式可以作为<a href="#adding-payment-methods">新的付款方式添加</a>或<a href="#updating-the-default-payment-method">用于更新默认付款方式</a>。你还可以立即使用付款方式标识符来<a href="#creating-subscriptions">创建新的订阅</a>。</p>
<blockquote>
<p><strong>注意</strong><br>
如果你想要了解有关设置意向和收集客户付款详细信息的更多信息，请<a href="https://stripe.com/docs/payments/save-and-reuse#php" target="_blank" rel="noopener noreferrer">查看 Stripe 提供的概述</a>。</p>
</blockquote>
<h4 id="单次收费的付款方式" tabindex="-1"><a class="header-anchor" href="#单次收费的付款方式"><span>单次收费的付款方式</span></a></h4>
<p>当针对客户的付款方式进行单次收费时，我们只需要一次使用付款方式标识符。由于 Stripe 的限制，你可能无法在单次收费中使用客户的存储默认付款方式。你必须允许客户使用 Stripe.js 库输入他们的付款方式详细信息。例如，考虑以下表单：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-holder-name<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token comment">&lt;!-- Stripe 元素占位符 --></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-element<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    处理付款</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在定义这样的表单后，可以使用 Stripe.js 库将<a href="https://stripe.com/docs/stripe-js" target="_blank" rel="noopener noreferrer">Stripe 元素</a>附加到表单中，并安全地收集客户的付款详细信息：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://js.stripe.com/v3/<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></span>
<span class="line"></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"></span>
<span class="line">    <span class="token keyword">const</span> stripe <span class="token operator">=</span> <span class="token function">Stripe</span><span class="token punctuation">(</span><span class="token string">'stripe-public-key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">const</span> elements <span class="token operator">=</span> stripe<span class="token punctuation">.</span><span class="token function">elements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token keyword">const</span> cardElement <span class="token operator">=</span> elements<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">'card'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    cardElement<span class="token punctuation">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string">'#card-element'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，可以验证卡片并使用<a href="https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method" target="_blank" rel="noopener noreferrer">Stripe 的 <code v-pre>createPaymentMethod</code> 方法</a>从 Stripe 获取安全的「付款方式标识符」：</p>
<div class="language-javascript line-numbers-mode" data-highlighter="prismjs" data-ext="js" data-title="js"><pre v-pre class="language-javascript"><code><span class="line"><span class="token keyword">const</span> cardHolderName <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'card-holder-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> cardButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'card-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">cardButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token punctuation">{</span> paymentMethod<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> stripe<span class="token punctuation">.</span><span class="token function">createPaymentMethod</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token string">'card'</span><span class="token punctuation">,</span> cardElement<span class="token punctuation">,</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token literal-property property">billing_details</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> cardHolderName<span class="token punctuation">.</span>value <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 向用户显示「error.message」...</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 卡片已成功验证...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果卡片验证成功，你可以将 <code v-pre>paymentMethod.id</code> 传递给你的 Laravel 应用程序并处理<a href="#simple-charge">单次收费</a>。</p>
<h3 id="获取付款方式" tabindex="-1"><a class="header-anchor" href="#获取付款方式"><span>获取付款方式</span></a></h3>
<p>在可账单化模型实例上的 <code v-pre>paymentMethods</code> 方法返回一个 <code v-pre>Laravel\Cashier\PaymentMethod</code> 实例的集合：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethods</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">paymentMethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，此方法将返回每种类型的付款方式。要检索特定类型的付款方式，可以将 <code v-pre>type</code> 作为参数传递给方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethods</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">paymentMethods</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sepa_debit'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要检索客户的默认付款方式，可以使用 <code v-pre>defaultPaymentMethod</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethod</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">defaultPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>使用 <code v-pre>findPaymentMethod</code> 方法可以检索附加到可账单化模型的特定付款方式：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethod</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findPaymentMethod</span><span class="token punctuation">(</span><span class="token variable">$paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="付款方式存在性" tabindex="-1"><a class="header-anchor" href="#付款方式存在性"><span>付款方式存在性</span></a></h3>
<p>要确定可账单化模型是否附加了默认付款方式到他们的帐户，请调用 <code v-pre>hasDefaultPaymentMethod</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasDefaultPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>hasPaymentMethod</code> 方法来确定可账单化模型是否至少附加了一个付款方式到他们的帐户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>此方法将确定可账单化模型是否有任何付款方式。要确定特定类型的付款方式是否存在于模型中，可以将 <code v-pre>type</code> 作为参数传递给方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasPaymentMethod</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sepa_debit'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="更新默认付款方式" tabindex="-1"><a class="header-anchor" href="#更新默认付款方式"><span>更新默认付款方式</span></a></h3>
<p><code v-pre>updateDefaultPaymentMethod</code> 方法可用于更新客户的默认付款方式信息。此方法接受一个 Stripe 付款方式标识符，并将新付款方式分配为默认的账单付款方式：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">updateDefaultPaymentMethod</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要将默认付款方式信息与 Stripe 中客户的默认付款方式信息同步，可以使用 <code v-pre>updateDefaultPaymentMethodFromStripe</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">updateDefaultPaymentMethodFromStripe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
客户的默认付款方式只能用于开具发票和创建新订阅。由于 Stripe 的限制，它可能无法用于单次收费。</p>
</blockquote>
<h3 id="添加付款方式" tabindex="-1"><a class="header-anchor" href="#添加付款方式"><span>添加付款方式</span></a></h3>
<p>要添加新的付款方式，你可以在可账单化模型上调用 <code v-pre>addPaymentMethod</code> 方法，传递付款方式标识符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">addPaymentMethod</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
要了解如何检索付款方式标识符，请查看<a href="#storing-payment-methods">付款方式存储文档</a>。</p>
</blockquote>
<h3 id="删除付款方式" tabindex="-1"><a class="header-anchor" href="#删除付款方式"><span>删除付款方式</span></a></h3>
<p>要删除付款方式，你可以在要删除的 <code v-pre>Laravel\Cashier\PaymentMethod</code> 实例上调用 <code v-pre>delete</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethod</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>deletePaymentMethod</code> 方法将从可账单化模型中删除特定的付款方式：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">deletePaymentMethod</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pm_visa'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>deletePaymentMethods</code> 方法将删除可账单化模型的所有付款方式信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">deletePaymentMethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，此方法将删除每种类型的付款方式。要删除特定类型的付款方式，可以将 <code v-pre>type</code> 作为参数传递给方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">deletePaymentMethods</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sepa_debit'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
如果用户有活跃订阅，你的应用程序不应允许他们删除他们的默认付款方式。</p>
</blockquote>
<h2 id="订阅" tabindex="-1"><a class="header-anchor" href="#订阅"><span>订阅</span></a></h2>
<p>订阅提供了一种为客户设置循环付款的方式。由 Cashier 管理的 Stripe 订阅支持多个订阅价格、订阅数量、试用期等功能。</p>
<h3 id="创建订阅" tabindex="-1"><a class="header-anchor" href="#创建订阅"><span>创建订阅</span></a></h3>
<p>要创建订阅，首先检索可账单化模型的实例，通常将是 <code v-pre>App\Models\User</code> 的实例。一旦检索到模型实例，可以使用 <code v-pre>newSubscription</code> 方法创建模型的订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>传递给 <code v-pre>newSubscription</code> 方法的第一个参数应该是订阅的内部类型。如果你的应用程序只提供单个订阅，你可以称之为 <code v-pre>default</code> 或 <code v-pre>primary</code>。这种订阅类型仅供内部应用程序使用，不应向用户显示。此外，它不应包含空格，并且在创建订阅后不应更改。第二个参数是用户要订阅的具体价格。这个值应该对应于 Stripe 中价格的标识符。</p>
<p><code v-pre>create</code> 方法接受<a href="#storing-payment-methods">Stripe 付款方式标识符</a>或 Stripe <code v-pre>PaymentMethod</code> 对象，将开始订阅，并更新你的数据库，其中包含可账单化模型的 Stripe 客户ID和其他相关的计费信息。</p>
<blockquote>
<p><strong>警告</strong><br>
直接将付款方式标识符传递给 <code v-pre>create</code> 订阅方法还将自动将其添加到用户存储的付款方式中。</p>
</blockquote>
<h3 id="通过发票电子邮件收取循环付款" tabindex="-1"><a class="header-anchor" href="#通过发票电子邮件收取循环付款"><span>通过发票电子邮件收取循环付款</span></a></h3>
<p>与自动收取客户的循环付款不同，你可以要求 Stripe 在每次客户的循环付款到期时向客户发送一封发票电子邮件。然后，客户可以在收到发票后手动支付。在通过发票收取循环付款时，客户无需提前提供付款方式：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">createAndSendInvoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>客户在取消订阅之前必须支付发票的时间取决于 <code v-pre>days_until_due</code> 选项。默认情况下，这是30天；但是，如果需要，你可以为此选项提供一个特定值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">createAndSendInvoice</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'days_until_due'</span> <span class="token operator">=></span> <span class="token number">30</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="订阅数量" tabindex="-1"><a class="header-anchor" href="#订阅数量"><span>订阅数量</span></a></h3>
<p>如果你想在创建订阅时为价格设置特定的<a href="https://stripe.com/docs/billing/subscriptions/quantities" target="_blank" rel="noopener noreferrer">数量</a>，你应该在创建订阅之前在订阅构建器上调用 <code v-pre>quantity</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">quantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="附加详情" tabindex="-1"><a class="header-anchor" href="#附加详情"><span>附加详情</span></a></h4>
<p>如果你想指定额外的<a href="https://stripe.com/docs/api/customers/create" target="_blank" rel="noopener noreferrer">客户</a>或<a href="https://stripe.com/docs/api/subscriptions/create" target="_blank" rel="noopener noreferrer">订阅</a>选项（由 Stripe 支持），你可以将它们作为第二个和第三个参数传递给 <code v-pre>create</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$email</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'metadata'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'note'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'一些额外信息。'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="优惠券" tabindex="-1"><a class="header-anchor" href="#优惠券"><span>优惠券</span></a></h4>
<p>如果你想在创建订阅时应用优惠券，你可以使用 <code v-pre>withCoupon</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">withCoupon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'code'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，如果你想应用<a href="https://stripe.com/docs/billing/subscriptions/discounts/codes" target="_blank" rel="noopener noreferrer">Stripe促销代码</a>，你可以使用 <code v-pre>withPromotionCode</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">withPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'promo_code_id'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>给定的促销代码ID应该是分配给促销代码的 Stripe API ID，而不是客户可见的促销代码。如果你需要根据给定的客户可见促销代码查找促销代码ID，你可以使用 <code v-pre>findPromotionCode</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 根据客户可见代码查找促销代码ID...</span></span>
<span class="line"><span class="token variable">$promotionCode</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'SUMMERSALE'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 根据客户可见代码查找活动促销代码ID...</span></span>
<span class="line"><span class="token variable">$promotionCode</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findActivePromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'SUMMERSALE'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上面的示例中，返回的 <code v-pre>$promotionCode</code> 对象是 <code v-pre>Laravel\Cashier\PromotionCode</code> 的实例。这个类装饰了一个底层的 <code v-pre>Stripe\PromotionCode</code> 对象。你可以通过调用 <code v-pre>coupon</code> 方法来获取与促销代码相关联的优惠券：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$coupon</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'SUMMERSALE'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">coupon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>优惠券实例允许你确定折扣金额以及优惠券是固定折扣还是基于百分比的折扣：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$coupon</span><span class="token operator">-></span><span class="token function">isPercentage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$coupon</span><span class="token operator">-></span><span class="token function">percentOff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">.</span><span class="token string single-quoted-string">'%'</span><span class="token punctuation">;</span> <span class="token comment">// 21.5%</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$coupon</span><span class="token operator">-></span><span class="token function">amountOff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// $5.99</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以检索当前应用于客户或订阅的折扣：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$discount</span> <span class="token operator">=</span> <span class="token variable">$billable</span><span class="token operator">-></span><span class="token function">discount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$discount</span> <span class="token operator">=</span> <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">discount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>返回的 <code v-pre>Laravel\Cashier\Discount</code> 实例装饰了一个底层的 <code v-pre>Stripe\Discount</code> 对象实例。你可以通过调用 <code v-pre>coupon</code> 方法来获取与该折扣相关联的优惠券：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$coupon</span> <span class="token operator">=</span> <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">discount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">coupon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想将新的优惠券或促销代码应用于客户或订阅，你可以通过 <code v-pre>applyCoupon</code> 或 <code v-pre>applyPromotionCode</code> 方法来实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$billable</span><span class="token operator">-></span><span class="token function">applyCoupon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'coupon_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$billable</span><span class="token operator">-></span><span class="token function">applyPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'promotion_code_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">applyCoupon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'coupon_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">applyPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'promotion_code_id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>请记住，你应该使用分配给促销代码的 Stripe API ID，而不是客户可见的促销代码。在特定时间内，只能向客户或订阅应用一个优惠券或促销代码。</p>
<p>有关更多信息，请参考 Stripe 关于<a href="https://stripe.com/docs/billing/subscriptions/coupons" target="_blank" rel="noopener noreferrer">优惠券</a>和<a href="https://stripe.com/docs/billing/subscriptions/coupons/codes" target="_blank" rel="noopener noreferrer">促销代码</a>的文档。</p>
<h3 id="添加订阅" tabindex="-1"><a class="header-anchor" href="#添加订阅"><span>添加订阅</span></a></h3>
<p>如果你想给已经有默认支付方式的客户添加订阅，你可以在订阅构建器上调用 <code v-pre>add</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="从stripe仪表板创建订阅" tabindex="-1"><a class="header-anchor" href="#从stripe仪表板创建订阅"><span>从Stripe仪表板创建订阅</span></a></h4>
<p>你也可以直接从Stripe仪表板创建订阅。这样做时，Cashier将同步新添加的订阅并将它们分配一个类型为 <code v-pre>default</code>。如果要自定义分配给仪表板创建的订阅的订阅类型，请<a href="#defining-webhook-event-handlers">定义Webhook事件处理程序</a>。</p>
<p>此外，你只能通过Stripe仪表板创建一种类型的订阅。如果你的应用程序提供使用不同类型的多个订阅，只能通过Stripe仪表板添加一种类型的订阅。</p>
<p>最后，你应该始终确保每种应用程序提供的订阅类型只添加一个活动订阅。如果客户有两个 <code v-pre>default</code> 订阅，Cashier只会使用最近添加的订阅，尽管两者都会与你的应用程序数据库同步。</p>
<h3 id="检查订阅状态" tabindex="-1"><a class="header-anchor" href="#检查订阅状态"><span>检查订阅状态</span></a></h3>
<p>一旦客户订阅了你的应用程序，你可以使用各种便利方法轻松检查他们的订阅状态。首先，<code v-pre>subscribed</code> 方法在客户有活动订阅时返回 <code v-pre>true</code>，即使订阅目前处于试用期内。<code v-pre>subscribed</code> 方法接受订阅类型作为其第一个参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>subscribed</code> 方法还可以作为<a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">路由中间件</a>的一个很好的选择，让你可以根据用户的订阅状态过滤对路由和控制器的访问：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Symfony<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>HttpFoundation<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">EnsureUserIsSubscribed</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理传入请求。</span>
<span class="line">  *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>Closure</span>(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 这个用户不是付费客户...</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想确定用户是否仍处于试用期内，你可以使用 <code v-pre>onTrial</code> 方法。这个方法可以用于确定是否应向用户显示警告，告诉他们他们仍处于试用期内：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>subscribedToProduct</code> 方法可用于确定用户是否订阅了给定产品，基于给定的 Stripe 产品标识符。在Stripe中，产品是价格的集合。在这个例子中，我们将确定用户的 <code v-pre>default</code> 订阅是否积极订阅了应用程序的「premium」产品。给定的 Stripe 产品标识符应该对应于Stripe仪表板中一个产品的标识符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribedToProduct</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'prod_premium'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过向 <code v-pre>subscribedToProduct</code> 方法传递一个数组，你可以确定用户的 <code v-pre>default</code> 订阅是否积极订阅了应用程序的「basic」或「premium」产品：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribedToProduct</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'prod_basic'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'prod_premium'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>subscribedToPrice</code> 方法可用于确定客户的订阅是否对应于给定的价格ID：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribedToPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_basic_monthly'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>recurring</code> 方法可用于确定用户当前是否订阅且不再处于试用期内：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">recurring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
如果用户有两个相同类型的订阅，<code v-pre>subscription</code> 方法始终会返回最近的订阅。例如，用户可能有两个类型为 <code v-pre>default</code> 的订阅记录；然而，其中一个订阅可能是旧的、已过期的订阅，而另一个是当前的、活动的订阅。最近的订阅将始终返回，而旧的订阅会保留在数据库中供历史审查。</p>
</blockquote>
<h4 id="取消订阅状态" tabindex="-1"><a class="header-anchor" href="#取消订阅状态"><span>取消订阅状态</span></a></h4>
<p>要确定用户曾经是活跃订阅者但已取消他们的订阅，你可以使用 <code v-pre>canceled</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以确定用户是否已取消订阅，但仍处于「宽限期」直到订阅完全到期。例如，如果用户在3月5日取消了原定于3月10日到期的订阅，则用户在3月10日之前处于「宽限期」。请注意，在此期间 <code v-pre>subscribed</code> 方法仍然返回 <code v-pre>true</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要确定用户是否已取消订阅且不再处于「宽限期」，你可以使用 <code v-pre>ended</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">ended</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不完整和过期状态" tabindex="-1"><a class="header-anchor" href="#不完整和过期状态"><span>不完整和过期状态</span></a></h4>
<p>如果订阅创建后需要进行第二次付款操作，则订阅将被标记为 <code v-pre>incomplete</code>。订阅状态存储在 Cashier 的 <code v-pre>subscriptions</code> 数据库表的 <code v-pre>stripe_status</code> 列中。</p>
<p>类似地，如果在更改价格时需要进行第二次付款操作，则订阅将被标记为 <code v-pre>past_due</code>。当订阅处于这两种状态之一时，直到客户确认付款为止，订阅将不处于活动状态。可以使用 billable 模型或订阅实例上的 <code v-pre>hasIncompletePayment</code> 方法来确定订阅是否存在不完整的付款：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当订阅存在不完整的付款时，你应该将用户引导至 Cashier 的付款确认页面，传递 <code v-pre>latestPayment</code> 标识符。你可以使用订阅实例上提供的 <code v-pre>latestPayment</code> 方法来检索这个标识符：</p>
<div class="language-html line-numbers-mode" data-highlighter="prismjs" data-ext="html" data-title="html"><pre v-pre class="language-html"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ route('cashier.payment', $subscription->latestPayment()->id) }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    请确认你的付款。</span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果希望在订阅处于 <code v-pre>past_due</code> 或 <code v-pre>incomplete</code> 状态时仍然将其视为活跃状态，可以使用 Cashier 提供的 <code v-pre>keepPastDueSubscriptionsActive</code> 和 <code v-pre>keepIncompleteSubscriptionsActive</code> 方法。通常，这些方法应该在 <code v-pre>App\Providers\AppServiceProvider</code> 的 <code v-pre>register</code> 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Register any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">keepPastDueSubscriptionsActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">keepIncompleteSubscriptionsActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
当订阅处于 <code v-pre>incomplete</code> 状态时，直到付款确认之前无法更改订阅。因此，当订阅处于 <code v-pre>incomplete</code> 状态时，<code v-pre>swap</code> 和 <code v-pre>updateQuantity</code> 方法将抛出异常。</p>
</blockquote>
<h4 id="订阅范围" tabindex="-1"><a class="header-anchor" href="#订阅范围"><span>订阅范围</span></a></h4>
<p>大多数订阅状态也作为查询范围可用，这样你可以轻松地查询处于特定状态的订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 获取所有活跃订阅...</span></span>
<span class="line"><span class="token variable">$subscriptions</span> <span class="token operator">=</span> <span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 获取用户的所有已取消订阅...</span></span>
<span class="line"><span class="token variable">$subscriptions</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscriptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>下面是可用的所有范围的完整列表：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">canceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">ended</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incomplete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notCanceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notOnGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">notOnTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pastDue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Subscription</span><span class="token operator">::</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">recurring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="更改价格" tabindex="-1"><a class="header-anchor" href="#更改价格"><span>更改价格</span></a></h3>
<p>当客户订阅你的应用程序后，他们可能偶尔想要更改到新的订阅价格。要将客户切换到新的价格，请将 Stripe 价格标识符传递给 <code v-pre>swap</code> 方法。在更改价格时，假设用户希望重新激活他们之前取消的订阅。给定的价格标识符应该对应于 Stripe 仪表板中可用的 Stripe 价格标识符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果客户正在试用期内，试用期将被保留。此外，如果订阅存在「数量」，该数量也将被保留。</p>
<p>如果你想要切换价格并取消客户当前正在进行的试用期，你可以调用 <code v-pre>skipTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">skipTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要切换价格并立即向客户开具发票，而不是等待他们的下一个计费周期，你可以使用 <code v-pre>swapAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swapAndInvoice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="比例调整" tabindex="-1"><a class="header-anchor" href="#比例调整"><span>比例调整</span></a></h4>
<p>默认情况下，在不同价格之间进行切换时，Stripe 会按比例调整费用。可以使用 <code v-pre>noProrate</code> 方法来更新订阅的价格，而不会按比例调整费用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>有关订阅比例调整的更多信息，请参考<a href="https://stripe.com/docs/billing/subscriptions/prorations" target="_blank" rel="noopener noreferrer">Stripe文档</a>。</p>
<blockquote>
<p><strong>警告</strong><br>
在执行 <code v-pre>swapAndInvoice</code> 方法之前执行 <code v-pre>noProrate</code> 方法将不会影响比例调整。发票将始终被开具。</p>
</blockquote>
<h3 id="订阅数量-1" tabindex="-1"><a class="header-anchor" href="#订阅数量-1"><span>订阅数量</span></a></h3>
<p>有时订阅会受到「数量」的影响。例如，一个项目管理应用程序可能会按每个项目每月 $10 收费。你可以使用 <code v-pre>incrementQuantity</code> 和 <code v-pre>decrementQuantity</code> 方法轻松增加或减少订阅数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 将当前数量增加五个...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 将当前数量减少五个...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>另外，你可以使用 <code v-pre>updateQuantity</code> 方法设置特定的数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>可以使用 <code v-pre>noProrate</code> 方法来更新订阅的数量，而不会按比例调整费用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>有关订阅数量的更多信息，请参考<a href="https://stripe.com/docs/subscriptions/quantities" target="_blank" rel="noopener noreferrer">Stripe文档</a>。</p>
<h4 id="多产品订阅的数量" tabindex="-1"><a class="header-anchor" href="#多产品订阅的数量"><span>多产品订阅的数量</span></a></h4>
<p>如果你的订阅是一个<a href="#subscriptions-with-multiple-products">具有多个产品的订阅</a>，你应该将你希望增加或减少数量的价格的ID作为第二个参数传递给增加/减少方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="具有多个产品的订阅" tabindex="-1"><a class="header-anchor" href="#具有多个产品的订阅"><span>具有多个产品的订阅</span></a></h3>
<p><a href="https://stripe.com/docs/billing/subscriptions/multiple-products" target="_blank" rel="noopener noreferrer">具有多个产品的订阅</a>允许你将多个计费产品分配给单个订阅。例如，假设你正在构建一个客户服务「帮助台」应用程序，基本订阅价格为每月 $10，但提供额外的每月 $15 的实时聊天附加产品。具有多个产品的订阅的信息存储在 Cashier 的 <code v-pre>subscription_items</code> 数据库表中。</p>
<p>你可以通过将价格数组作为 <code v-pre>newSubscription</code> 方法的第二个参数传递来为给定订阅指定多个产品：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上面的示例中，客户将有两个价格附加到他们的 <code v-pre>default</code> 订阅上。两个价格将在各自的计费间隔上收费。如果需要，你可以使用 <code v-pre>quantity</code> 方法为每个价格指定特定数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">quantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想要向现有订阅添加另一个价格，你可以调用订阅的 <code v-pre>addPrice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的示例将添加新价格，客户将在下一个计费周期收取费用。如果你想要立即向客户收费，你可以使用 <code v-pre>addPriceAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addPriceAndInvoice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想要添加一个具有特定数量的价格，你可以将数量作为 <code v-pre>addPrice</code> 或 <code v-pre>addPriceAndInvoice</code> 方法的第二个参数传递：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>removePrice</code> 方法从订阅中移除价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">removePrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
你不能移除订阅中的最后一个价格。相反，你应该简单地取消订阅。</p>
</blockquote>
<h4 id="替换价格" tabindex="-1"><a class="header-anchor" href="#替换价格"><span>替换价格</span></a></h4>
<p>你也可以更改附加到具有多个产品的订阅的价格。例如，假设客户有一个 <code v-pre>price_basic</code> 订阅和一个 <code v-pre>price_chat</code> 附加产品，你想要将客户从 <code v-pre>price_basic</code> 升级到 <code v-pre>price_pro</code> 价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_pro'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在执行上面的示例时，<code v-pre>price_basic</code> 的基础订阅项目将被删除，<code v-pre>price_chat</code> 的项目将被保留。此外，将为 <code v-pre>price_pro</code> 创建一个新的订阅项目。</p>
<p>你还可以通过向 <code v-pre>swap</code> 方法传递键/值对数组来指定订阅项目选项。例如，你可能需要指定订阅价格的数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'price_pro'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'quantity'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'price_chat'</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想在订阅中替换单个价格，可以使用订阅项本身的 <code v-pre>swap</code> 方法。如果你想保留订阅的其他价格上的所有现有元数据，这种方法特别有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">findItemOrFail</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_basic'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_pro'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="按比例计价" tabindex="-1"><a class="header-anchor" href="#按比例计价"><span>按比例计价</span></a></h4>
<p>默认情况下，当在具有多个产品的订阅中添加或删除价格时，Stripe会按比例计费。如果你想进行价格调整而不按比例计费，应在价格操作中链接 <code v-pre>noProrate</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">removePrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="数量" tabindex="-1"><a class="header-anchor" href="#数量"><span>数量</span></a></h4>
<p>如果你想在单个订阅价格上更新数量，可以使用<a href="#subscription-quantity">现有的数量方法</a>，通过将价格的ID作为额外参数传递给方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
当订阅有多个价格时，<code v-pre>Subscription</code> 模型上的 <code v-pre>stripe_price</code> 和 <code v-pre>quantity</code> 属性将为 <code v-pre>null</code>。要访问各个价格属性，应使用 <code v-pre>Subscription</code> 模型上可用的 <code v-pre>items</code> 关系。</p>
</blockquote>
<h4 id="订阅项" tabindex="-1"><a class="header-anchor" href="#订阅项"><span>订阅项</span></a></h4>
<p>当订阅有多个价格时，它将在你的数据库的 <code v-pre>subscription_items</code> 表中存储多个订阅「项」。你可以通过订阅的 <code v-pre>items</code> 关系访问这些项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$subscriptionItem</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">items</span><span class="token operator">-></span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 检索特定项的 Stripe 价格和数量...</span></span>
<span class="line"><span class="token variable">$stripePrice</span> <span class="token operator">=</span> <span class="token variable">$subscriptionItem</span><span class="token operator">-></span><span class="token property">stripe_price</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$quantity</span> <span class="token operator">=</span> <span class="token variable">$subscriptionItem</span><span class="token operator">-></span><span class="token property">quantity</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也可以使用 <code v-pre>findItemOrFail</code> 方法检索特定的价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$subscriptionItem</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">findItemOrFail</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_chat'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="多个订阅" tabindex="-1"><a class="header-anchor" href="#多个订阅"><span>多个订阅</span></a></h4>
<p>Stripe允许你的客户同时拥有多个订阅。例如，你可能经营一家健身房，提供游泳订阅和举重订阅，每个订阅可能有不同的定价。当然，客户应该能够订阅其中一个或两个计划。</p>
<p>当你的应用程序创建订阅时，可以向 <code v-pre>newSubscription</code> 方法提供订阅的类型。类型可以是表示用户正在启动的订阅类型的任何字符串：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/swimming/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">price</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_swimming_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个例子中，我们为客户启动了一个月度游泳订阅。然而，他们可能希望在以后切换到年度订阅。在调整客户的订阅时，我们可以简单地在 <code v-pre>swimming</code> 订阅上替换价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_swimming_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当然，你也可以完全取消订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'swimming'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="计量计费" tabindex="-1"><a class="header-anchor" href="#计量计费"><span>计量计费</span></a></h4>
<p><a href="https://stripe.com/docs/billing/subscriptions/metered-billing" target="_blank" rel="noopener noreferrer">计量计费</a>允许你根据客户在计费周期内的产品使用量向他们收费。例如，你可以根据客户每月发送的短信或电子邮件数量来收费。</p>
<p>要开始使用计量计费，首先需要在Stripe仪表板中创建一个具有计量价格的新产品。然后，使用 <code v-pre>meteredPrice</code> 将计量价格ID添加到客户订阅中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">meteredPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_metered'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也可以通过 <a href="#checkout">Stripe Checkout</a> 来启动计量订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">meteredPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_metered'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-checkout-view'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'checkout'</span> <span class="token operator">=></span> <span class="token variable">$checkout</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="报告使用情况" tabindex="-1"><a class="header-anchor" href="#报告使用情况"><span>报告使用情况</span></a></h4>
<p>当客户使用你的应用程序时，你需要向Stripe报告他们的使用情况，以便能够准确计费。要增加计量订阅的使用量，可以使用 <code v-pre>reportUsage</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">reportUsage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，会在计费周期中添加一个「使用数量」为1。或者，你可以传递一个特定的「使用量」以添加到客户在计费周期内的使用量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">reportUsage</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你的应用程序在单个订阅上提供多个价格，你需要使用 <code v-pre>reportUsageFor</code> 方法来指定要报告使用情况的计量价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">reportUsageFor</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_metered'</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有时，你可能需要更新先前报告的使用情况。为此，可以将时间戳或 <code v-pre>DateTimeInterface</code> 实例作为 <code v-pre>reportUsage</code> 的第二个参数传递。这样做时，Stripe将更新在给定时间报告的使用情况。只要给定的日期和时间仍在当前计费周期内，就可以继续更新先前的使用记录：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">reportUsage</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token variable">$timestamp</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="检索使用记录" tabindex="-1"><a class="header-anchor" href="#检索使用记录"><span>检索使用记录</span></a></h4>
<p>要检索客户的过去使用情况，可以使用订阅实例的 <code v-pre>usageRecords</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$usageRecords</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">usageRecords</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你的应用程序在单个订阅上提供多个价格，你可以使用 <code v-pre>usageRecordsFor</code> 方法来指定要检索使用记录的计量价格：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$usageRecords</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">usageRecordsFor</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_metered'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>usageRecords</code> 和 <code v-pre>usageRecordsFor</code> 方法返回一个包含使用记录的关联数组的 Collection 实例。你可以遍历这个数组以显示客户的总使用量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">@<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$usageRecords</span> <span class="token keyword">as</span> <span class="token variable">$usageRecord</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-</span> Period Starting<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$usageRecord</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'period'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'start'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token operator">-</span> Period Ending<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$usageRecord</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'period'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'end'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token operator">-</span> Total Usage<span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$usageRecord</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'total_usage'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="line">@<span class="token keyword">endforeach</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要查看返回的所有使用数据以及如何使用Stripe的基于游标的分页，请参考<a href="https://stripe.com/docs/api/usage_records/subscription_item_summary_list" target="_blank" rel="noopener noreferrer">官方Stripe API文档</a>。</p>
<h4 id="订阅税费" tabindex="-1"><a class="header-anchor" href="#订阅税费"><span>订阅税费</span></a></h4>
<blockquote>
<p><strong>警告</strong><br>
代替手动计算税率，你可以使用 <a href="#tax-configuration">Stripe Tax 自动计算税费</a></p>
</blockquote>
<p>为了指定用户在订阅上支付的税率，你应该在可账单模型上实现 <code v-pre>taxRates</code> 方法，并返回一个包含Stripe税率ID的数组。你可以在 <a href="https://dashboard.stripe.com/test/tax-rates" target="_blank" rel="noopener noreferrer">Stripe仪表板</a> 中定义这些税率：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 用户订阅应用的税率。</span>
<span class="line">  *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, string></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">taxRates</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'txr_id'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>taxRates</code> 方法使你能够根据每个客户应用税率，这对于跨多个国家和税率的用户群可能很有帮助。</p>
<p>如果你提供具有多个产品的订阅，你可以通过在可账单模型上实现 <code v-pre>priceTaxRates</code> 方法来为每个价格定义不同的税率：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 用户订阅应用的税率。</span>
<span class="line">  *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;string, array&lt;int, string>></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">priceTaxRates</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'price_monthly'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'txr_id'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
<code v-pre>taxRates</code> 方法仅适用于订阅费用。如果你使用Cashier进行「一次性」收费，你需要在那时手动指定税率。</p>
</blockquote>
<h4 id="同步税率" tabindex="-1"><a class="header-anchor" href="#同步税率"><span>同步税率</span></a></h4>
<p>当更改 <code v-pre>taxRates</code> 方法返回的硬编码税率ID时，用户现有订阅的税费设置将保持不变。如果你希望使用新的 <code v-pre>taxRates</code> 值更新现有订阅的税费值，你应该在用户的订阅实例上调用 <code v-pre>syncTaxRates</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">syncTaxRates</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>这也将同步具有多个产品的订阅的任何项目税率。如果你的应用程序提供具有多个产品的订阅，你应该确保你的可账单模型实现了上文中讨论的 <code v-pre>priceTaxRates</code> 方法。</p>
<h4 id="免税" tabindex="-1"><a class="header-anchor" href="#免税"><span>免税</span></a></h4>
<p>Cashier 还提供了 <code v-pre>isNotTaxExempt</code>、<code v-pre>isTaxExempt</code> 和 <code v-pre>reverseChargeApplies</code> 方法，用于确定客户是否免税。这些方法将调用Stripe API来确定客户的税收豁免状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isTaxExempt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isNotTaxExempt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">reverseChargeApplies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
这些方法也适用于任何 <code v-pre>Laravel\Cashier\Invoice</code> 对象。但是，当在 <code v-pre>Invoice</code> 对象上调用时，这些方法将确定发票创建时的豁免状态。</p>
</blockquote>
<h4 id="订阅锚定日期" tabindex="-1"><a class="header-anchor" href="#订阅锚定日期"><span>订阅锚定日期</span></a></h4>
<p>默认情况下，计费周期锚点是订阅创建的日期，或者如果使用试用期，则是试用期结束的日期。如果你想修改计费锚定日期，可以使用 <code v-pre>anchorBillingCycleOn</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$anchor</span> <span class="token operator">=</span> <span class="token class-name static-context">Carbon</span><span class="token operator">::</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'first day of next month'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">anchorBillingCycleOn</span><span class="token punctuation">(</span><span class="token variable">$anchor</span><span class="token operator">-></span><span class="token function">startOfDay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要了解更多关于管理订阅计费周期的信息，请查阅<a href="https://stripe.com/docs/billing/subscriptions/billing-cycle" target="_blank" rel="noopener noreferrer">Stripe计费周期文档</a>。</p>
<h4 id="取消订阅" tabindex="-1"><a class="header-anchor" href="#取消订阅"><span>取消订阅</span></a></h4>
<p>要取消订阅，请在用户的订阅上调用 <code v-pre>cancel</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当取消订阅时，Cashier会自动设置你的 <code v-pre>subscriptions</code> 数据库表中的 <code v-pre>ends_at</code> 列。这一列用于确定 <code v-pre>subscribed</code> 方法何时应开始返回 <code v-pre>false</code>。</p>
<p>例如，如果客户在3月1日取消订阅，但订阅直到3月5日才结束，<code v-pre>subscribed</code> 方法将继续返回 <code v-pre>true</code>，直到3月5日。这是因为通常允许用户在其计费周期结束前继续使用应用程序。</p>
<p>你可以使用 <code v-pre>onGracePeriod</code> 方法确定用户是否已取消订阅但仍处于「宽限期」：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你希望立即取消订阅，请在用户的订阅上调用 <code v-pre>cancelNow</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你希望立即取消订阅并对任何剩余未计费的计量使用量或新的/待处理的调整发票项目进行结算，请在用户的订阅上调用 <code v-pre>cancelNowAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelNowAndInvoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你也可以选择在特定时间取消订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelAt</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>最后，在删除相关的用户模型之前，你应该始终取消用户订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="恢复订阅" tabindex="-1"><a class="header-anchor" href="#恢复订阅"><span>恢复订阅</span></a></h4>
<p>如果客户取消了他们的订阅，而你希望恢复它，你可以在订阅上调用 <code v-pre>resume</code> 方法。客户必须仍处于他们的「宽限期」内才能恢复订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果客户取消了订阅，然后在订阅完全到期之前恢复了订阅，客户不会立即被收费。相反，他们的订阅将重新激活，并且他们将按照原始的计费周期进行收费。</p>
<h2 id="订阅试用期" tabindex="-1"><a class="header-anchor" href="#订阅试用期"><span>订阅试用期</span></a></h2>
<h3 id="预先收集付款方式" tabindex="-1"><a class="header-anchor" href="#预先收集付款方式"><span>预先收集付款方式</span></a></h3>
<p>如果你想向客户提供试用期，同时仍然在前期收集付款方式信息，你应该在创建订阅时使用 <code v-pre>trialDays</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/subscribe'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">trialDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这个方法会在数据库中的订阅记录上设置试用期结束日期，并指示Stripe在此日期之后开始向客户收费。使用 <code v-pre>trialDays</code> 方法时，Cashier会覆盖Stripe中为价格配置的任何默认试用期。</p>
<blockquote>
<p><strong>警告</strong><br>
如果客户的订阅在试用期结束日期之前未取消，他们将在试用期到期后立即收费，因此你应该确保通知用户他们的试用期结束日期。</p>
</blockquote>
<p><code v-pre>trialUntil</code> 方法允许你提供一个指定试用期应该结束的 <code v-pre>DateTime</code> 实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">trialUntil</span><span class="token punctuation">(</span><span class="token class-name static-context">Carbon</span><span class="token operator">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用用户实例的 <code v-pre>onTrial</code> 方法或订阅实例的 <code v-pre>onTrial</code> 方法来确定用户是否在他们的试用期内。下面的两个示例是等效的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>endTrial</code> 方法立即结束订阅试用期：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">endTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要确定现有试用期是否已过期，你可以使用 <code v-pre>hasExpiredTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasExpiredTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasExpiredTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="在-stripe-cashier-中定义试用天数" tabindex="-1"><a class="header-anchor" href="#在-stripe-cashier-中定义试用天数"><span>在 Stripe / Cashier 中定义试用天数</span></a></h4>
<p>你可以选择在Stripe仪表板中定义价格的试用天数，或者始终通过Cashier显式传递它们。如果你选择在Stripe中定义价格的试用天数，你应该知道新订阅，包括过去曾有订阅的客户的新订阅，将始终获得试用期，除非你显式调用 <code v-pre>skipTrial()</code> 方法。</p>
<h3 id="无需预先收集付款方式" tabindex="-1"><a class="header-anchor" href="#无需预先收集付款方式"><span>无需预先收集付款方式</span></a></h3>
<p>如果你想在不预先收集用户付款方式信息的情况下提供试用期，你可以将用户记录中的 <code v-pre>trial_ends_at</code> 列设置为你期望的试用结束日期。这通常在用户注册过程中完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'trial_ends_at'</span> <span class="token operator">=></span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
请确保在你的可计费模型类定义中为 <code v-pre>trial_ends_at</code> 属性添加一个<a href="https://learnku.com/docs/laravel/11.x/eloquent-mutators#date-casting" target="_blank" rel="noopener noreferrer">日期转换</a>。</p>
</blockquote>
<p>Cashier将这种类型的试用期称为「通用试用期」，因为它不附加到任何现有订阅。如果当前日期未超过 <code v-pre>trial_ends_at</code> 的值，可计费模型实例上的 <code v-pre>onTrial</code> 方法将返回 <code v-pre>true</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户在试用期内...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当你准备为用户创建实际订阅时，你可以像往常一样使用 <code v-pre>newSubscription</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要检索用户的试用结束日期，你可以使用 <code v-pre>trialEndsAt</code> 方法。如果用户正在试用中，该方法将返回一个 Carbon 日期实例，如果他们不在试用中，则返回 <code v-pre>null</code>。如果你想获取除默认订阅以外其他特定订阅的试用结束日期，你还可以传递一个可选的订阅类型参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$trialEndsAt</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">trialEndsAt</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你希望明确知道用户是否在他们的「通用」试用期内并且尚未创建实际订阅，你可以使用 <code v-pre>onGenericTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onGenericTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户在他们的「通用」试用期内...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="延长试用期" tabindex="-1"><a class="header-anchor" href="#延长试用期"><span>延长试用期</span></a></h3>
<p><code v-pre>extendTrial</code> 方法允许你在创建订阅后延长订阅的试用期。如果试用期已经过期并且客户已经为订阅付费，你仍然可以为他们提供延长的试用期。试用期内的时间将从客户的下一个账单中扣除：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$subscription</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 从现在起延长试用期 7 天...</span></span>
<span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">extendTrial</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 在试用期上再增加 5 天...</span></span>
<span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">extendTrial</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token property">trial_ends_at</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="处理-stripe-webhooks" tabindex="-1"><a class="header-anchor" href="#处理-stripe-webhooks"><span>处理 Stripe Webhooks</span></a></h2>
<blockquote>
<p><strong>注意</strong><br>
你可以使用 <a href="https://stripe.com/docs/stripe-cli" target="_blank" rel="noopener noreferrer">Stripe CLI</a> 在本地开发过程中帮助测试 Webhooks。</p>
</blockquote>
<p>Stripe 可以通过 Webhooks 通知你的应用程序各种事件。默认情况下，Cashier 服务提供程序会自动注册一个指向 Cashier 的 Webhook 控制器的路由。这个控制器将处理所有传入的 Webhook 请求。</p>
<p>默认情况下，Cashier 的 Webhook 控制器将自动处理取消订阅（由你的 Stripe 设置定义）次数过多的失败扣款、客户更新、客户删除、订阅更新和支付方式更改；然而，正如我们将很快发现的那样，你可以扩展这个控制器来处理任何你喜欢的Stripe Webhook 事件。</p>
<p>为确保你的应用程序能够处理 Stripe Webhooks，请确保在 Stripe 控制面板中配置Webhook URL。默认情况下，Cashier 的 Webhook 控制器响应于<code v-pre>/stripe/webhook</code> URL路径。在 Stripe 控制面板中应启用的所有 Webhooks 的完整列表包括：</p>
<ul>
<li><code v-pre>customer.subscription.created</code></li>
<li><code v-pre>customer.subscription.updated</code></li>
<li><code v-pre>customer.subscription.deleted</code></li>
<li><code v-pre>customer.updated</code></li>
<li><code v-pre>customer.deleted</code></li>
<li><code v-pre>payment_method.automatically_updated</code></li>
<li><code v-pre>invoice.payment_action_required</code></li>
<li><code v-pre>invoice.payment_succeeded</code></li>
</ul>
<p>为方便起见，Cashier 包含一个 <code v-pre>cashier:webhook</code> Artisan 命令。该命令将在Stripe 中创建一个 Webhook，监听 Cashier 所需的所有事件：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan cashier:webhook</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，创建的 Webhook 将指向由<code v-pre>APP_URL</code>环境变量和 Cashier 附带的<code v-pre>cashier.webhook</code>路由定义的 URL。如果你想使用不同的 URL，可以在调用命令时提供 <code v-pre>--url</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan cashier:webhook <span class="token parameter variable">--url</span> <span class="token string">"https://example.com/stripe/webhook"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>创建的 Webhook 将使用与你的 Cashier 版本兼容的 Stripe API 版本。如果你想使用不同的 Stripe 版本，你可以提供 <code v-pre>--api-version</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan cashier:webhook --api-version<span class="token operator">=</span><span class="token string">"2019-12-03"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>创建后，Webhook 将立即生效。如果你希望创建 Webhook，但在准备好之前将其禁用，你可以在调用命令时提供 <code v-pre>--disabled</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan cashier:webhook <span class="token parameter variable">--disabled</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
确保使用 Cashier 包含的 <a href="#verifying-webhook-signatures">Webhook 签名验证</a> 中间件保护传入的 Stripe Webhook 请求。</p>
</blockquote>
<h4 id="webhooks-和-csrf-保护" tabindex="-1"><a class="header-anchor" href="#webhooks-和-csrf-保护"><span>Webhooks 和 CSRF 保护</span></a></h4>
<p>由于 Stripe Webhooks 需要绕过 Laravel 的 <a href="https://learnku.com/docs/laravel/11.x/csrf" target="_blank" rel="noopener noreferrer">CSRF 保护</a>，你应确保 Laravel 不会尝试验证传入的 Stripe Webhooks 的 CSRF 令牌。为此，你应在应用程序的 <code v-pre>bootstrap/app.php</code> 文件中排除 <code v-pre>stripe/*</code> 从 CSRF 保护中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">-></span><span class="token function">withMiddleware</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Middleware</span> <span class="token variable">$middleware</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$middleware</span><span class="token operator">-></span><span class="token function">validateCsrfTokens</span><span class="token punctuation">(</span><span class="token argument-name">except</span><span class="token punctuation">:</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'stripe/*'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="定义-webhook-事件处理程序" tabindex="-1"><a class="header-anchor" href="#定义-webhook-事件处理程序"><span>定义 Webhook 事件处理程序</span></a></h3>
<p>Cashier 自动处理订阅取消、失败扣款和其他常见的 Stripe Webhook 事件。但是，如果你有其他 Webhook 事件需要处理，你可以通过监听 Cashier 分发的以下事件来处理：</p>
<ul>
<li><code v-pre>Laravel\Cashier\Events\WebhookReceived</code></li>
<li><code v-pre>Laravel\Cashier\Events\WebhookHandled</code></li>
</ul>
<p>这两个事件包含了完整的 Stripe Webhook 负载。例如，如果你希望处理 <code v-pre>invoice.payment_succeeded</code> Webhook，你可以注册一个 <a href="https://learnku.com/docs/laravel/11.x/events#defining-listeners" target="_blank" rel="noopener noreferrer">监听器</a> 来处理该事件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>WebhookReceived</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">StripeEventListener</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理接收到的 Stripe Webhooks。</span>
<span class="line">  */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebhookReceived</span> <span class="token variable">$event</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-></span><span class="token property">payload</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'invoice.payment_succeeded'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 处理传入的事件...</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="验证-webhook-签名" tabindex="-1"><a class="header-anchor" href="#验证-webhook-签名"><span>验证 Webhook 签名</span></a></h3>
<p>为了保护你的 Webhooks，你可以使用<a href="https://stripe.com/docs/webhooks/signatures" target="_blank" rel="noopener noreferrer">Stripe 的 Webhook 签名</a>。为了方便起见，Cashier 自动包含了一个中间件，用于验证传入的 Stripe Webhook 请求是否有效。</p>
<p>要启用 Webhook 验证，请确保在你的应用程序的 <code v-pre>.env</code> 文件中设置了 <code v-pre>STRIPE_WEBHOOK_SECRET</code> 环境变量。Webhook 的 <code v-pre>secret</code> 可以从你的 Stripe 账户仪表板中获取。</p>
<h2 id="单笔收费" tabindex="-1"><a class="header-anchor" href="#单笔收费"><span>单笔收费</span></a></h2>
<h3 id="简单收费" tabindex="-1"><a class="header-anchor" href="#简单收费"><span>简单收费</span></a></h3>
<p>如果你想对客户进行一次性收费，你可以在可账单模型实例上使用 <code v-pre>charge</code> 方法。你需要将第二个参数作为 <code v-pre>charge</code> 方法的支付方法标识符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/purchase'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$stripeCharge</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token property">paymentMethodId</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>charge</code> 方法接受一个数组作为其第三个参数，允许你传递任何你希望传递给底层Stripe收费创建的选项。有关在创建收费时可用的选项的更多信息，请参阅<a href="https://stripe.com/docs/api/charges/create" target="_blank" rel="noopener noreferrer">Stripe文档</a>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'custom_option'</span> <span class="token operator">=></span> <span class="token variable">$value</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也可以在没有底层客户或用户的情况下使用 <code v-pre>charge</code> 方法。为此，在你的应用程序的可账单模型的新实例上调用 <code v-pre>charge</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$stripeCharge</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果收费失败，<code v-pre>charge</code> 方法将抛出异常。如果收费成功，方法将返回一个 <code v-pre>Laravel\Cashier\Payment</code> 的实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">try</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
<code v-pre>charge</code> 方法接受以你的应用程序使用的货币的最低单位为单位的支付金额。例如，如果客户以美元支付，金额应该以美分为单位指定。</p>
</blockquote>
<h3 id="带发票的收费" tabindex="-1"><a class="header-anchor" href="#带发票的收费"><span>带发票的收费</span></a></h3>
<p>有时候你可能需要进行一次性收费并为客户提供PDF发票。<code v-pre>invoicePrice</code> 方法可以帮助你实现这一目的。例如，让我们为客户开具五件新衬衫的发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoicePrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>发票将立即从用户的默认支付方式中扣款。<code v-pre>invoicePrice</code> 方法还接受一个数组作为其第三个参数。这个数组包含发票项目的计费选项。方法接受的第四个参数也是一个数组，应该包含发票本身的计费选项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoicePrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'discounts'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token punctuation">[</span><span class="token string single-quoted-string">'coupon'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'SUMMER21SALE'</span><span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'default_tax_rates'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'txr_id'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>类似于 <code v-pre>invoicePrice</code>，你可以使用 <code v-pre>tabPrice</code> 方法通过将项目添加到客户的「标签」来为多个项目（每张发票最多250个项目）创建一次性收费，然后向客户开具发票。例如，我们可以为客户开具五件衬衫和两只杯子的发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tabPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tabPrice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_mug'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>invoiceFor</code> 方法对客户的默认支付方式进行「一次性」收费：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoiceFor</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'一次性费用'</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>虽然 <code v-pre>invoiceFor</code> 方法可供使用，但建议你使用预定义价格的 <code v-pre>invoicePrice</code> 和 <code v-pre>tabPrice</code> 方法。这样做可以让你在Stripe仪表板中更好地了解关于每种产品销售的分析和数据。</p>
<blockquote>
<p><strong>警告</strong><br>
<code v-pre>invoice</code>、<code v-pre>invoicePrice</code> 和 <code v-pre>invoiceFor</code> 方法将创建一个Stripe发票，该发票将重试失败的扣款尝试。如果你不希望发票重试失败的扣款，请在首次扣款失败后使用Stripe API关闭它们。</p>
</blockquote>
<h3 id="创建支付意图" tabindex="-1"><a class="header-anchor" href="#创建支付意图"><span>创建支付意图</span></a></h3>
<p>你可以通过在可账单模型实例上调用 <code v-pre>pay</code> 方法来创建一个新的Stripe支付意图。调用此方法将创建一个包含在 <code v-pre>Laravel\Cashier\Payment</code> 实例中的支付意图：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/pay'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">pay</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'amount'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$payment</span><span class="token operator">-></span><span class="token property">client_secret</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>创建支付意图后，你可以将客户端密钥返回给你的应用前端，以便用户可以在他们的浏览器中完成支付。要了解有关使用Stripe支付意图构建整个支付流程的更多信息，请查阅<a href="https://stripe.com/docs/payments/accept-a-payment?platform=web" target="_blank" rel="noopener noreferrer">Stripe文档</a>。</p>
<p>在使用 <code v-pre>pay</code> 方法时，默认启用的支付方式将在你的Stripe仪表板中对客户可用。或者，如果你只想允许使用一些特定的支付方式，你可以使用 <code v-pre>payWith</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/pay'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">payWith</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'amount'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'card'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'bancontact'</span><span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$payment</span><span class="token operator">-></span><span class="token property">client_secret</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>[!WARNING]<br>
<code v-pre>pay</code> 和 <code v-pre>payWith</code> 方法接受以你的应用程序使用的货币的最低单位为单位的支付金额。例如，如果客户以美元支付，金额应该以美分为单位指定。</p>
</blockquote>
<h3 id="退款" tabindex="-1"><a class="header-anchor" href="#退款"><span>退款</span></a></h3>
<p>如果你需要退款Stripe的一笔交易，你可以使用 <code v-pre>refund</code> 方法。该方法将接受Stripe的<a href="#payment-methods-for-single-charges">支付意图ID</a>作为其第一个参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethodId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">refund</span><span class="token punctuation">(</span><span class="token variable">$payment</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="发票" tabindex="-1"><a class="header-anchor" href="#发票"><span>发票</span></a></h2>
<h3 id="获取发票" tabindex="-1"><a class="header-anchor" href="#获取发票"><span>获取发票</span></a></h3>
<p>你可以使用 <code v-pre>invoices</code> 方法轻松地获取可账单模型的发票数组。<code v-pre>invoices</code> 方法返回一个 <code v-pre>Laravel\Cashier\Invoice</code> 实例的集合：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoices</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想在结果中包括待处理的发票，你可以使用 <code v-pre>invoicesIncludingPending</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoices</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoicesIncludingPending</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>findInvoice</code> 方法通过发票ID检索特定发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">findInvoice</span><span class="token punctuation">(</span><span class="token variable">$invoiceId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="显示发票信息" tabindex="-1"><a class="header-anchor" href="#显示发票信息"><span>显示发票信息</span></a></h4>
<p>在为客户列出发票时，你可以使用发票的方法来显示相关的发票信息。例如，你可以希望在表格中列出每张发票，让用户可以轻松下载其中任何一张：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>table<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$invoices</span> <span class="token keyword">as</span> <span class="token variable">$invoice</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">&lt;</span>tr<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$invoice</span><span class="token operator">-></span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toFormattedDateString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$invoice</span><span class="token operator">-></span><span class="token function">total</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token operator">&lt;</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"/user/invoice/{{ <span class="token interpolation"><span class="token variable">$invoice</span><span class="token operator">-></span><span class="token property">id</span></span> }}"</span><span class="token operator">></span>下载<span class="token operator">&lt;</span><span class="token operator">/</span>a<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">        <span class="token operator">&lt;</span><span class="token operator">/</span>tr<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">endforeach</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>table<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="即将到期的发票" tabindex="-1"><a class="header-anchor" href="#即将到期的发票"><span>即将到期的发票</span></a></h3>
<p>要获取客户的即将到期的发票，你可以使用 <code v-pre>upcomingInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">upcomingInvoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>类似地，如果客户有多个订阅，你也可以为特定订阅获取即将到期的发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">upcomingInvoice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="预览订阅发票" tabindex="-1"><a class="header-anchor" href="#预览订阅发票"><span>预览订阅发票</span></a></h3>
<p>使用 <code v-pre>previewInvoice</code> 方法，你可以在进行价格更改之前预览发票。这将允许你确定当进行特定价格更改时，客户的发票会是什么样子：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">previewInvoice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以向 <code v-pre>previewInvoice</code> 方法传递价格数组，以便预览具有多个新价格的发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoice</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">previewInvoice</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_yearly'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_metered'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="生成发票pdf" tabindex="-1"><a class="header-anchor" href="#生成发票pdf"><span>生成发票PDF</span></a></h3>
<p>在生成发票PDF之前，你应该使用Composer安装Dompdf库，这是Cashier的默认发票渲染器：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">composer <span class="token keyword">require</span> dompdf<span class="token operator">/</span>dompdf</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>在路由或控制器中，你可以使用 <code v-pre>downloadInvoice</code> 方法来生成给定发票的PDF下载。这个方法将自动生成下载发票所需的正确HTTP响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user/invoice/{invoice}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$invoiceId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">downloadInvoice</span><span class="token punctuation">(</span><span class="token variable">$invoiceId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，发票上的所有数据都来自于Stripe中存储的客户和发票数据。文件名基于你的 <code v-pre>app.name</code> 配置值。但是，你可以通过将数组作为 <code v-pre>downloadInvoice</code> 方法的第二个参数来自定义部分数据。这个数组允许你自定义诸如公司和产品详细信息之类的信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">downloadInvoice</span><span class="token punctuation">(</span><span class="token variable">$invoiceId</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'vendor'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Your Company'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'product'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Your Product'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'street'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Main Str. 1'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'location'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'2000 Antwerp, Belgium'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'phone'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'+32 499 00 00 00'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'info@example.com'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'url'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'https://example.com'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'vendorVat'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'BE123456789'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>downloadInvoice</code> 方法还允许通过第三个参数设置自定义文件名。这个文件名将自动添加 <code v-pre>.pdf</code> 后缀：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">downloadInvoice</span><span class="token punctuation">(</span><span class="token variable">$invoiceId</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'my-invoice'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="自定义发票渲染器" tabindex="-1"><a class="header-anchor" href="#自定义发票渲染器"><span>自定义发票渲染器</span></a></h4>
<p>Cashier还可以使用自定义发票渲染器。默认情况下，Cashier使用 <code v-pre>DompdfInvoiceRenderer</code> 实现，它利用 <a href="https://github.com/dompdf/dompdf" target="_blank" rel="noopener noreferrer">dompdf</a> PHP库来生成Cashier的发票。但是，你可以通过实现 <code v-pre>Laravel\Cashier\Contracts\InvoiceRenderer</code> 接口来使用任何你希望的渲染器。例如，你可以希望使用API调用到第三方PDF渲染服务来渲染发票PDF：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Http</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>InvoiceRenderer</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Invoice</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ApiInvoiceRenderer</span> <span class="token keyword">implements</span> <span class="token class-name">InvoiceRenderer</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 渲染给定的发票并返回原始的PDF字节。</span>
<span class="line">  */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">render</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Invoice</span> <span class="token variable">$invoice</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$data</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$options</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$html</span> <span class="token operator">=</span> <span class="token variable">$invoice</span><span class="token operator">-></span><span class="token function">view</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Http</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'https://example.com/html-to-pdf'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'html'</span> <span class="token operator">=></span> <span class="token variable">$html</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">body</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦你实现了发票渲染器合同，你应该在你的应用程序的 <code v-pre>config/cashier.php</code> 配置文件中更新 <code v-pre>cashier.invoices.renderer</code> 配置值。这个配置值应该设置为你自定义渲染器实现的类名。</p>
<h2 id="结账" tabindex="-1"><a class="header-anchor" href="#结账"><span>结账</span></a></h2>
<p>Cashier Stripe还支持<a href="https://stripe.com/payments/checkout" target="_blank" rel="noopener noreferrer">Stripe Checkout</a>。Stripe Checkout通过提供一个预构建的托管支付页面，简化了实现自定义接受支付页面的痛苦。</p>
<p>以下文档包含了如何开始在Cashier中使用Stripe Checkout的信息。要了解更多关于Stripe Checkout的信息，你还应考虑查看<a href="https://stripe.com/docs/payments/checkout" target="_blank" rel="noopener noreferrer">Stripe自己的Checkout文档</a>。</p>
<h3 id="产品结账" tabindex="-1"><a class="header-anchor" href="#产品结账"><span>产品结账</span></a></h3>
<p>你可以在可账单模型上使用 <code v-pre>checkout</code> 方法为已在你的Stripe仪表板中创建的现有产品执行结账。<code v-pre>checkout</code> 方法将启动一个新的Stripe Checkout会话。默认情况下，你需要传递一个Stripe价格ID：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果需要，你也可以指定产品数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_tshirt'</span> <span class="token operator">=></span> <span class="token number">15</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当客户访问此路由时，他们将被重定向到Stripe的结账页面。默认情况下，当用户成功完成或取消购买时，他们将被重定向到你的 <code v-pre>home</code> 路由位置，但你可以使用 <code v-pre>success_url</code> 和 <code v-pre>cancel_url</code> 选项指定自定义回调URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_tshirt'</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-success-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-cancel-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在定义你的 <code v-pre>success_url</code> 结账选项时，你可以指示Stripe在调用URL时将结账会话ID作为查询字符串参数添加。为此，将字面字符串 <code v-pre>{CHECKOUT_SESSION_ID}</code> 添加到你的 <code v-pre>success_url</code> 查询字符串中。Stripe将用实际的结账会话ID替换这个占位符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Stripe<span class="token punctuation">\</span>Checkout<span class="token punctuation">\</span>Session</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Stripe<span class="token punctuation">\</span>Customer</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'price_tshirt'</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token operator">.</span><span class="token string single-quoted-string">'?session_id={CHECKOUT_SESSION_ID}'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-cancel'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/checkout-success'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$checkoutSession</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">stripe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">checkout</span><span class="token operator">-></span><span class="token property">sessions</span><span class="token operator">-></span><span class="token function">retrieve</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'session_id'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout.success'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'checkoutSession'</span> <span class="token operator">=></span> <span class="token variable">$checkoutSession</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'checkout-success'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="促销代码" tabindex="-1"><a class="header-anchor" href="#促销代码"><span>促销代码</span></a></h4>
<p>默认情况下，Stripe Checkout不允许<a href="https://stripe.com/docs/billing/subscriptions/discounts/codes" target="_blank" rel="noopener noreferrer">用户可兑换的促销代码</a>。幸运的是，有一种简单的方法可以为你的结账页面启用这些促销代码。为此，你可以调用 <code v-pre>allowPromotionCodes</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">allowPromotionCodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="单次收费结账" tabindex="-1"><a class="header-anchor" href="#单次收费结账"><span>单次收费结账</span></a></h3>
<p>你还可以为未在Stripe仪表板中创建的临时产品执行简单的收费。为此，你可以在可账单模型上使用 <code v-pre>checkoutCharge</code> 方法，并传递一个可收费金额、产品名称和可选数量。当客户访问此路由时，他们将被重定向到Stripe的结账页面：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/charge-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkoutCharge</span><span class="token punctuation">(</span><span class="token number">1200</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'T-Shirt'</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
使用 <code v-pre>checkoutCharge</code> 方法时，Stripe将始终在你的Stripe仪表板中创建一个新的产品和价格。因此，我们建议你提前在Stripe仪表板中创建产品，并改用 <code v-pre>checkout</code> 方法。</p>
</blockquote>
<h3 id="订阅结账" tabindex="-1"><a class="header-anchor" href="#订阅结账"><span>订阅结账</span></a></h3>
<blockquote>
<p><strong>警告</strong><br>
使用Stripe Checkout进行订阅需要在Stripe仪表板中启用 <code v-pre>customer.subscription.created</code> Webhook。该Webhook将在你的数据库中创建订阅记录并存储所有相关的订阅项目。</p>
</blockquote>
<p>你也可以使用Stripe Checkout来启动订阅。在使用Cashier的订阅构建器方法定义订阅后，你可以调用 <code v-pre>checkout</code> 方法。当客户访问此路由时，他们将被重定向到Stripe的结账页面：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>与产品结账一样，你可以自定义成功和取消的URL：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-success-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-cancel-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，你也可以为订阅结账启用促销代码：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/subscription-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">allowPromotionCodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
不幸的是，当开始订阅时，Stripe Checkout不支持所有订阅计费选项。在Stripe Checkout会话期间，使用订阅构建器上的 <code v-pre>anchorBillingCycleOn</code> 方法、设置按比例计价行为或设置付款行为都不会产生任何效果。请参阅<a href="https://stripe.com/docs/api/checkout/sessions/create" target="_blank" rel="noopener noreferrer">Stripe Checkout会话API文档</a>以查看可用的参数。</p>
</blockquote>
<h4 id="stripe-checkout和试用期" tabindex="-1"><a class="header-anchor" href="#stripe-checkout和试用期"><span>Stripe Checkout和试用期</span></a></h4>
<p>当构建使用Stripe Checkout完成的订阅时，你当然可以定义一个试用期：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">trialDays</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然而，试用期必须至少为48小时，这是Stripe Checkout支持的最短试用时间。</p>
<h4 id="订阅和webhooks" tabindex="-1"><a class="header-anchor" href="#订阅和webhooks"><span>订阅和Webhooks</span></a></h4>
<p>请记住，Stripe和Cashier通过Webhooks更新订阅状态，因此当客户在输入付款信息后返回应用程序时，可能会出现订阅尚未激活的情况。为了处理这种情况，你可能希望显示一条消息，告知用户他们的付款或订阅正在等待处理。</p>
<h3 id="收集税号" tabindex="-1"><a class="header-anchor" href="#收集税号"><span>收集税号</span></a></h3>
<p>Checkout还支持收集客户的税号。要在结账会话上启用此功能，请在创建会话时调用 <code v-pre>collectTaxIds</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$checkout</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">collectTaxIds</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">checkout</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当调用此方法时，客户将可以看到一个新复选框，允许他们指示是否以公司名义购买。如果是，他们将有机会提供他们的税号。</p>
<blockquote>
<p><strong>警告</strong><br>
如果你已经在应用程序的服务提供者中配置了<a href="#tax-configuration">自动税收</a>，那么此功能将自动启用，无需调用 <code v-pre>collectTaxIds</code> 方法。</p>
</blockquote>
<h3 id="访客结账" tabindex="-1"><a class="header-anchor" href="#访客结账"><span>访客结账</span></a></h3>
<p>使用 <code v-pre>Checkout::guest</code> 方法，你可以为你的应用程序中没有「账户」的访客启动结账会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Checkout</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">Checkout</span><span class="token operator">::</span><span class="token function">guest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-success-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-cancel-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>类似于为现有用户创建结账会话时，你可以利用 <code v-pre>Laravel\Cashier\CheckoutBuilder</code> 实例上提供的其他方法来自定义访客结账会话：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Checkout</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/product-checkout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">Checkout</span><span class="token operator">::</span><span class="token function">guest</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">withPromotionCode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'promo-code'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_tshirt'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'success_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-success-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'cancel_url'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'your-cancel-route'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>完成访客结账后，Stripe可以发送一个 <code v-pre>checkout.session.completed</code> 的Webhook事件，所以确保<a href="https://dashboard.stripe.com/webhooks" target="_blank" rel="noopener noreferrer">配置你的Stripe Webhook</a>以确实将此事件发送到你的应用程序。一旦在Stripe仪表板中启用了Webhook，你可以<a href="#handling-stripe-webhooks">使用Cashier处理Webhook</a>。Webhook负载中包含的对象将是一个<a href="https://stripe.com/docs/api/checkout/sessions/object" target="_blank" rel="noopener noreferrer"><code v-pre>checkout</code>对象</a>，你可以检查该对象以完成客户的订单。</p>
<h2 id="处理失败支付" tabindex="-1"><a class="header-anchor" href="#处理失败支付"><span>处理失败支付</span></a></h2>
<p>有时，订阅或单笔付款可能会失败。当发生这种情况时，Cashier将抛出一个 <code v-pre>Laravel\Cashier\Exceptions\IncompletePayment</code> 异常，通知你发生了这种情况。在捕获此异常后，你有两种选择如何继续。</p>
<p>首先，你可以将客户重定向到Cashier中包含的专用支付确认页面。该页面已经有一个通过Cashier的服务提供者注册的关联命名路由。因此，你可以捕获 <code v-pre>IncompletePayment</code> 异常并将用户重定向到支付确认页面：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Exceptions<span class="token punctuation">\</span>IncompletePayment</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">try</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$subscription</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'price_monthly'</span><span class="token punctuation">)</span></span>
<span class="line">                            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IncompletePayment</span> <span class="token variable">$exception</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token string single-quoted-string">'cashier.payment'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">[</span><span class="token variable">$exception</span><span class="token operator">-></span><span class="token property">payment</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'redirect'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在支付确认页面上，客户将被提示重新输入他们的信用卡信息，并执行Stripe要求的任何其他操作，比如「3D Secure」确认。确认支付后，用户将被重定向到上面指定的 <code v-pre>redirect</code> 参数提供的URL。重定向时，将向URL添加 <code v-pre>message</code>（字符串）和 <code v-pre>success</code>（整数）查询字符串变量。当前支付页面支持以下支付方式类型：</p>
<ul>
<li>信用卡</li>
<li>支付宝</li>
<li>Bancontact</li>
<li>BECS直接借记</li>
<li>EPS</li>
<li>Giropay</li>
<li>iDEAL</li>
<li>SEPA直接借记</li>
</ul>
<p>或者，你可以允许Stripe为你处理支付确认。在这种情况下，你可以在Stripe仪表板中<a href="https://dashboard.stripe.com/account/billing/automatic" target="_blank" rel="noopener noreferrer">设置Stripe的自动账单邮件</a>，而不是重定向到支付确认页面。然而，如果捕获到 <code v-pre>IncompletePayment</code> 异常，你仍应通知用户他们将收到一封包含进一步支付确认说明的电子邮件。</p>
<p>以下方法可能会抛出支付异常：在使用 <code v-pre>Billable</code> 特性的模型上的 <code v-pre>charge</code>、<code v-pre>invoiceFor</code> 和 <code v-pre>invoice</code> 方法。在与订阅交互时，<code v-pre>SubscriptionBuilder</code> 上的 <code v-pre>create</code> 方法，以及 <code v-pre>Subscription</code> 和 <code v-pre>SubscriptionItem</code> 模型上的 <code v-pre>incrementAndInvoice</code> 和 <code v-pre>swapAndInvoice</code> 方法可能会抛出不完整支付异常。</p>
<p>可以使用可计费模型或订阅实例上的 <code v-pre>hasIncompletePayment</code> 方法来确定现有订阅是否存在不完整支付：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以通过检查异常实例上的 <code v-pre>payment</code> 属性来推导不完整支付的具体状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Exceptions<span class="token punctuation">\</span>IncompletePayment</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">try</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'pm_card_threeDSecure2Required'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IncompletePayment</span> <span class="token variable">$exception</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 获取支付意图状态...</span></span>
<span class="line">    <span class="token variable">$exception</span><span class="token operator">-></span><span class="token property">payment</span><span class="token operator">-></span><span class="token property">status</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 检查特定条件...</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$exception</span><span class="token operator">-></span><span class="token property">payment</span><span class="token operator">-></span><span class="token function">requiresPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">elseif</span> <span class="token punctuation">(</span><span class="token variable">$exception</span><span class="token operator">-></span><span class="token property">payment</span><span class="token operator">-></span><span class="token function">requiresConfirmation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="确认支付" tabindex="-1"><a class="header-anchor" href="#确认支付"><span>确认支付</span></a></h3>
<p>某些支付方法需要额外数据才能确认支付。例如，SEPA支付方法在支付过程中需要额外的「授权」数据。你可以使用 <code v-pre>withPaymentConfirmationOptions</code> 方法将这些数据提供给Cashier：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">withPaymentConfirmationOptions</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'mandate_data'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'...'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'price_xxx'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以查阅<a href="https://stripe.com/docs/api/payment_intents/confirm" target="_blank" rel="noopener noreferrer">Stripe API文档</a>以查看确认支付时接受的所有选项。</p>
<h2 id="强制客户认证" tabindex="-1"><a class="header-anchor" href="#强制客户认证"><span>强制客户认证</span></a></h2>
<p>如果你的业务或你的某位客户位于欧洲，你将需要遵守欧盟的强制客户认证（SCA）规定。这些规定是欧盟于2019年9月实施的，旨在防止支付欺诈。幸运的是，Stripe和Cashier已经为构建符合SCA标准的应用程序做好了准备。</p>
<blockquote>
<p><strong>警告</strong><br>
在开始之前，请查阅<a href="https://stripe.com/guides/strong-customer-authentication" target="_blank" rel="noopener noreferrer">Stripe关于PSD2和SCA的指南</a>以及他们关于新SCA API的<a href="https://stripe.com/docs/strong-customer-authentication" target="_blank" rel="noopener noreferrer">文档</a>。</p>
</blockquote>
<h3 id="需要额外确认的支付" tabindex="-1"><a class="header-anchor" href="#需要额外确认的支付"><span>需要额外确认的支付</span></a></h3>
<p>SCA规定通常需要额外的验证来确认和处理支付。当发生这种情况时，Cashier将抛出一个 <code v-pre>Laravel\Cashier\Exceptions\IncompletePayment</code> 异常，通知你需要额外验证。如何处理这些异常的更多信息可以在<a href="#handling-failed-payments">处理失败支付</a>的文档中找到。</p>
<p>由Stripe或Cashier呈现的支付确认屏幕可能会针对特定银行或卡发行商的支付流程进行定制，并可能包括额外的卡确认、临时小额扣款、单独的设备验证或其他形式的验证。</p>
<h4 id="不完整和过期状态-1" tabindex="-1"><a class="header-anchor" href="#不完整和过期状态-1"><span>不完整和过期状态</span></a></h4>
<p>当支付需要额外确认时，订阅将保持在 <code v-pre>不完整（incomplete）</code> 或 <code v-pre>过期（past_due）</code> 状态，如其 <code v-pre>stripe_status</code> 数据库列所示。一旦支付确认完成，并且你的应用程序通过Stripe的Webhook收到通知，Cashier将自动激活客户的订阅。</p>
<p>有关 <code v-pre>不完整（incomplete）</code> 和 <code v-pre>过期（past_due）</code> 状态的更多信息，请参考我们关于这些状态的<a href="#incomplete-and-past-due-status">额外文档</a>。</p>
<h3 id="离线支付通知" tabindex="-1"><a class="header-anchor" href="#离线支付通知"><span>离线支付通知</span></a></h3>
<p>由于SCA规定要求客户偶尔验证他们的付款细节，即使他们的订阅仍然有效，Cashier可以在需要离线支付确认时向客户发送通知。例如，当订阅续订时可能会发生这种情况。通过将 <code v-pre>CASHIER_PAYMENT_NOTIFICATION</code> 环境变量设置为通知类，可以启用Cashier的付款通知。默认情况下，此通知被禁用。当然，Cashier包含一个你可以用于此目的的通知类，但如果需要，你可以自由提供自己的通知类：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">CASHIER_PAYMENT_NOTIFICATION</span><span class="token punctuation">=</span><span class="token value attr-value">Laravel\Cashier\Notifications\ConfirmPayment</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>为确保离线支付确认通知被传递，请验证为你的应用程序配置了<a href="#handling-stripe-webhooks">Stripe Webhooks</a>，并且在你的Stripe仪表板中启用了 <code v-pre>invoice.payment_action_required</code> Webhook。此外，你的 <code v-pre>Billable</code> 模型还应该使用 Laravel 的 <code v-pre>Illuminate\Notifications\Notifiable</code> 特性。</p>
<blockquote>
<p><strong>警告</strong><br>
即使客户手动进行需要额外确认的支付，通知也会被发送。不幸的是，Stripe无法知道支付是手动完成还是「离线」完成。但是，如果客户在确认支付后访问付款页面，他们将简单地看到「支付成功」消息。客户不会被允许意外确认相同的付款两次并产生意外的第二笔费用。</p>
</blockquote>
<h2 id="stripe-sdk" tabindex="-1"><a class="header-anchor" href="#stripe-sdk"><span>Stripe SDK</span></a></h2>
<p>Cashier的许多对象都是Stripe SDK对象的封装。如果你想直接与Stripe对象交互，你可以使用 <code v-pre>asStripe</code> 方法方便地检索它们：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$stripeSubscription</span> <span class="token operator">=</span> <span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">asStripeSubscription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$stripeSubscription</span><span class="token operator">-></span><span class="token property">application_fee_percent</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$stripeSubscription</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以使用 <code v-pre>updateStripeSubscription</code> 方法直接更新 Stripe 订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token function">updateStripeSubscription</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'application_fee_percent'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想直接使用 <code v-pre>Stripe\StripeClient</code> 客户端，你可以在 <code v-pre>Cashier</code> 类上调用 <code v-pre>stripe</code> 方法。例如，你可以使用这个方法访问 <code v-pre>StripeClient</code> 实例，并从你的 Stripe 账户中检索价格列表：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$prices</span> <span class="token operator">=</span> <span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">stripe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">prices</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>在测试使用 Cashier 的应用程序时，你可以模拟对 Stripe API 的实际 HTTP 请求；但是，这需要你部分重新实现 Cashier 的行为。因此，我们建议允许你的测试访问实际的 Stripe API。虽然这会更慢一些，但可以更有信心地确保你的应用程序按预期工作，任何慢速测试可以放在它们自己的 Pest / PHPUnit 测试组中。</p>
<p>在测试时，请记住 Cashier 本身已经有一个很好的测试套件，因此你应该专注于测试你自己应用程序的订阅和付款流程，而不是每个底层 Cashier 行为。</p>
<p>要开始，将你的 Stripe 测试密钥的<strong>测试</strong>版本添加到你的 <code v-pre>phpunit.xml</code> 文件中：</p>
<div class="language-xml line-numbers-mode" data-highlighter="prismjs" data-ext="xml" data-title="xml"><pre v-pre class="language-xml"><code><span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>env</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>STRIPE_SECRET<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sk_test_&lt;your-key><span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>现在，每当你在测试中与 Cashier 交互时，它将向你的 Stripe 测试环境发送实际的 API 请求。为方便起见，你应该在 Stripe 测试账户中预先填充订阅/价格，以便在测试中使用。</p>
<blockquote>
<p><strong>注意</strong><br>
为了测试各种计费场景，比如信用卡拒绝和失败，你可以使用 Stripe 提供的广泛范围的<a href="https://stripe.com/docs/testing" target="_blank" rel="noopener noreferrer">测试卡号和令牌</a>。</p>
</blockquote>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/billingmd/16715" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/bi...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/billingmd/16715" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/bi...</a></p>
</blockquote>
</div></template>


